Skip to content

Commit b8d7977

Browse files
author
Gita Vahdatinia
authored
Reorg orb and add opsgenie notifications (#6)
1 parent a3c1fc6 commit b8d7977

17 files changed

+629
-16
lines changed

.circleci/config.yml

+84-13
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,93 @@
11
version: 2.1
22

3-
executors:
4-
validate:
5-
resource_class: small
6-
docker:
7-
- image: circleci/circleci-cli:latest
3+
orbs:
4+
utils: coda/utils@<<pipeline.parameters.dev-orb-version>>
5+
orb-tools: circleci/[email protected]
6+
bats: circleci/[email protected]
7+
shellcheck: circleci/[email protected]
8+
9+
# Pipeline Parameters
10+
## These parameters are used internally by orb-tools.
11+
parameters:
12+
run-integration-tests:
13+
description: An internal flag to prevent integration test from running before a development version has been created.
14+
type: boolean
15+
default: false
16+
dev-orb-version:
17+
description: >
18+
The development version of the orb to test.
19+
A "dev:alpha" version must exist for the initial pipeline run.
20+
type: string
21+
default: "dev:alpha"
22+
23+
commands:
24+
25+
826
jobs:
9-
validate:
10-
executor: validate
27+
integration-test-notify:
28+
docker:
29+
- image: cimg/base:stable
30+
steps:
31+
- checkout
32+
- utils/notify:
33+
on_success: true
34+
35+
integration-test-slack:
36+
docker:
37+
- image: cimg/base:stable
38+
steps:
39+
- checkout
40+
- utils/slack-notify-waiting-for-approval:
41+
slack_bot_token: ${PUSH_REMINDER_BOT_TOKEN}
42+
43+
integration-test-cancel-older-jobs:
44+
docker:
45+
- image: cimg/base:stable
1146
steps:
1247
- checkout
13-
- run:
14-
name: "Validate ORB config"
15-
command: circleci orb validate config.yml
48+
- utils/cancel-older-awaiting-approvals
1649

1750
workflows:
18-
version: 2
19-
commit_validation:
51+
test-pack:
52+
unless: << pipeline.parameters.run-integration-tests >>
53+
jobs:
54+
- orb-tools/pack
55+
- shellcheck/check:
56+
dir: ./src/scripts
57+
- bats/run:
58+
path: ./src/tests
59+
- hold-for-dev-publish:
60+
type: approval
61+
requires:
62+
- orb-tools/pack
63+
- bats/run
64+
- shellcheck/check
65+
# Publish development version of the orb.
66+
- orb-tools/publish-dev:
67+
orb-name: coda/utils
68+
context: orb-publishing
69+
requires: [hold-for-dev-publish]
70+
# dev:${CIRCLE_SHA1:0:7} version of your orb
71+
- orb-tools/trigger-integration-tests-workflow:
72+
name: trigger-integration-dev
73+
context: orb-publishing
74+
requires:
75+
- orb-tools/publish-dev
76+
77+
integration-test_deploy:
78+
when: << pipeline.parameters.run-integration-tests >>
2079
jobs:
21-
- validate
80+
- integration-test-notify
81+
- integration-test-slack
82+
- utils/cancel-older-awaiting-approvals
83+
- orb-tools/dev-promote-prod-from-commit-subject:
84+
orb-name: coda/utils
85+
context: orb-publishing
86+
add-pr-comment: false
87+
fail-if-semver-not-indicated: true
88+
publish-version-tag: false
89+
requires:
90+
- integration-test-notify
91+
- integration-test-slack
92+
- utils/cancel-older-awaiting-approvals
2293

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# orb.yml is "packed" from source, and not published directly from the repository.
2+
src/orb.yml

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2019 Coda Project
3+
Copyright (c) 2020 Coda Project
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
1-
# circleci-utils
21

3-
[CircleCI Orb](https://circleci.com/docs/2.0/reusing-config) containing a set of utilities for controlling CircleCI workflows & builds.
2+
# CircleCI Utils
3+
4+
5+
[![CircleCI Build Status](https://circleci.com/gh/kr-project/circleci-utils.svg?style=shield "CircleCI Build Status")](https://circleci.com/gh/kr-project/circleci-utils) [![CircleCI Orb Version](https://img.shields.io/badge/endpoint.svg?url=https://badges.circleci.io/orb/coda/utils)](https://circleci.com/orbs/registry/orb/coda/utils) [![GitHub License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://raw.githubusercontent.com/kr-project/circleci-utils/master/LICENSE) [![CircleCI Community](https://img.shields.io/badge/community-CircleCI%20Discuss-343434.svg)](https://discuss.circleci.com/c/ecosystem/orbs)
6+
7+
[Example Usage](src/examples/example.yml)
8+
### How to Publish
9+
* Create and push a branch with your new features.
10+
* When ready to publish a new production version, create a Pull Request from fore _feature branch_ to `master`.
11+
* The title of the pull request must contain a special semver tag: `[semver:<segement>]` where `<segment>` is replaced by one of the following values.
12+
13+
| Increment | Description|
14+
| ----------| -----------|
15+
| major | Issue a 1.0.0 incremented release|
16+
| minor | Issue a x.1.0 incremented release|
17+
| patch | Issue a x.x.1 incremented release|
18+
| skip | Do not issue a release|
19+
20+
Example: `[semver:major]`
21+
22+
* Squash and merge. Ensure the semver tag is preserved and entered as a part of the commit message.
23+
* On merge, after manual approval, the orb will automatically be published to the Orb Registry.
24+
25+
### How to Publish Dev Version
26+
To manually pack your `orb.yml`, you can run `circleci orb pack . > orb.yml` at the `@orb.yml` level.
27+
28+
```
29+
cd src
30+
circleci orb pack . > orb.yml
31+
circleci orb publish orb.yml coda/utils@dev:<your_branch_name>
32+
```

src/@orb.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2.1
2+
3+
description: >
4+
Utility orb for Coda
5+
Allows for:
6+
- Push alerts to opsgenie
7+
- Push Slack notifications
8+
- Cancel older CI alerts waiting for approval
9+
10+
display:
11+
source_url: "https://github.com/kr-project/circleci-utils"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
description: |
2+
Cancel all older pipelines waiting on manual approval.
3+
Depends on jq being present.
4+
parameters:
5+
circle_token:
6+
default: ${CIRCLECI_TOKEN}
7+
description: |
8+
Env var of a token granted read access to the CircleCI api
9+
type: string
10+
vcs:
11+
description: |
12+
Defaults to "gh", but allows other version control systems.
13+
type: string
14+
default: gh
15+
steps:
16+
- run:
17+
name: Cancel older pipelines waiting on manual approval.
18+
command: <<include(scripts/cancel_older_approvals.sh)>>
19+
environment:
20+
vcs: <<parameters.vcs>>
21+
CIRCLECI_TOKEN: <<parameters.circle_token>>

src/commands/notify.yml

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
description: Send build results to Opsgenie API, with detailed information
2+
parameters:
3+
CODA_USER_ROSTER_TABLE_URL:
4+
description: |
5+
Fully qualified API URL to a table containing CIRCLECI_USERNAMEs to email aliases. Must be of the form
6+
https://coda.io/apis/v1/docs/<DOCID>/tables/<TABLEID>/rows.
7+
type: string
8+
default: https://staging.coda.io/apis/v1/docs/s2i6oFeghW/tables/grid-QGyaiXZDwu/rows
9+
CODA_CIRCLECI_USER_NAME_COL:
10+
description: |
11+
Coda columnId of the column storing the CircleCI username in the CODA_USER_ROSTER_TABLE_URL document.
12+
type: string
13+
default: c-6ni4kHGNwE
14+
CODA_CIRCLECI_USER_ALIAS_COL:
15+
description: |
16+
Coda columnId of the column storing the user alias (when using EMAIL_DOMAIN), or fully qualified email.
17+
type: string
18+
default: c-26If9Zttyp
19+
endpoint:
20+
default: OPSGENIE_WEBHOOK
21+
description: Enter either your Full URL value that you copied in Opsgenie
22+
Integration Page
23+
type: env_var_name
24+
on_failure:
25+
default: false
26+
description: Failure information of circleci build
27+
type: boolean
28+
on_success:
29+
default: true
30+
description: Success information of circleci build
31+
type: boolean
32+
coda_api_token:
33+
default: ${CODA_API_TOKEN}
34+
description: |
35+
Env var of a token granted read access to the CODA_USER_ROSTER_TABLE_URL document.
36+
type: string
37+
EMAIL_DOMAIN:
38+
description: |
39+
Optional email domain for users within the workspace. Must be specified if user aliases are not fully qualified.
40+
type: string
41+
default: coda.io
42+
circle_token:
43+
default: ${CIRCLECI_TOKEN}
44+
description: |
45+
Env var of a token granted read access to the CircleCI api
46+
type: string
47+
steps:
48+
- run:
49+
name: Fetch User Information
50+
when: always
51+
command: <<include(scripts/fetch_user_handles.sh)>>
52+
environment:
53+
CODA_API_TOKEN: << parameters.coda_api_token >>
54+
CODA_CIRCLECI_USER_ALIAS_COL: <<parameters.CODA_CIRCLECI_USER_ALIAS_COL>>
55+
CODA_CIRCLECI_USER_NAME_COL: <<parameters.CODA_CIRCLECI_USER_NAME_COL>>
56+
CODA_USER_ROSTER_TABLE_URL: <<parameters.CODA_USER_ROSTER_TABLE_URL>>
57+
EMAIL_DOMAIN: <<parameters.EMAIL_DOMAIN>>
58+
- run:
59+
name: Get diff url
60+
when: on_fail
61+
command: <<include(scripts/get_lkg_hash.sh)>>
62+
environment:
63+
CIRCLE_TOKEN: << parameters.circle_token >>
64+
- run:
65+
command: |
66+
echo '{}' | jq '{
67+
"message": "[CircleCI] [#\(env.CIRCLE_PREVIOUS_BUILD_NUM)]: workflow \(env.CIRCLE_BRANCH) stage \(env.CIRCLE_STAGE) job \(env.CIRCLE_JOB)",
68+
"alias": "\(env.CIRCLE_PROJECT_REPONAME)/\(env.CIRCLE_BRANCH)#\(env.CIRCLE_JOB) ",
69+
"description":"See \(env.CIRCLE_BUILD_URL) for more details. ",
70+
"outcome": "unknown",
71+
"username": env.CIRCLE_USERNAME,
72+
"details": {
73+
"build_number":env.CIRCLE_PREVIOUS_BUILD_NUM,
74+
"build_url": env.CIRCLE_BUILD_URL
75+
}
76+
}' > /tmp/raw-webhook.json
77+
name: Bundle build info into webhook payload
78+
when: always
79+
- when:
80+
condition: $USER_EMAIL
81+
steps:
82+
- run:
83+
command: |
84+
cat /tmp/raw-webhook.json | jq --arg USER_EMAIL $USER_EMAIL '.details.username += $USER_EMAIL ' > /tmp/webhook_temp.json
85+
mv /tmp/webhook_temp.json /tmp/raw-webhook.json
86+
name: Add user email to Webhook
87+
- when:
88+
condition: $DIFF_URL
89+
steps:
90+
- run:
91+
command: |
92+
cat /tmp/raw-webhook.json | jq --arg DIFF_URL $DIFF_URL '.description += " Compare with last passing commit: '$DIFF_URL'"' > /tmp/webhook_temp.json
93+
mv /tmp/webhook_temp.json /tmp/raw-webhook.json
94+
name: Add latest git hash to Webhook
95+
- when:
96+
condition: <<parameters.on_success>>
97+
steps:
98+
- run:
99+
command: |
100+
cat /tmp/raw-webhook.json | jq '.payload.outcome="success"' > /tmp/webhook.json
101+
curl -X POST -H"Content-Type:application/json" -H "Authorization: GenieKey ${OPS_GENIE_API_KEY}" -d @/tmp/webhook.json https://api.opsgenie.com/v2/alerts
102+
name: Notify $<<parameters.endpoint>> with Success Webhook
103+
when: on_success
104+
- when:
105+
condition: <<parameters.on_failure>>
106+
steps:
107+
- run:
108+
command: |
109+
cat /tmp/raw-webhook.json | jq '.payload.outcome="failed"' > /tmp/webhook.json
110+
curl -X POST -H"Content-Type:application/json" -H "Authorization: GenieKey ${OPS_GENIE_API_KEY}" -d @/tmp/webhook.json https://api.opsgenie.com/v2/alerts
111+
name: Notify $<<parameters.endpoint>> with Failure Webhook
112+
when: on_fail
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
description: |
2+
Notifies the current workflow owner that their workflow is pending approval to proceed.
3+
Depends on jq being present.
4+
5+
Setup:
6+
1. Create Coda document with a table containing columns `circleci alias` (ex: github username) and `email`, and populate this table with information for each github user.
7+
3. Find the docId, tableId, and columnIds for the circleci user alias and email columnIds.
8+
4. Create a Coda API token for this document at https://coda.io/account - limit the token to read access to the target table.
9+
5. Setup a Slack Bot account with scopes `users:read`, `users:read.email`, and `chat:write`.
10+
6. Configure orb based on required args
11+
parameters:
12+
CODA_USER_ROSTER_TABLE_URL:
13+
description: |
14+
Fully qualified API URL to a table containing CIRCLECI_USERNAMEs to email aliases. Must be of the form
15+
https://coda.io/apis/v1/docs/<DOCID>/tables/<TABLEID>/rows.
16+
type: string
17+
default: https://staging.coda.io/apis/v1/docs/s2i6oFeghW/tables/grid-QGyaiXZDwu/rows
18+
coda_api_token:
19+
description: |
20+
Env var of a token granted read access to the CODA_USER_ROSTER_TABLE_URL document.
21+
type: string
22+
default: ${CODA_API_TOKEN}
23+
CODA_CIRCLECI_USER_NAME_COL:
24+
description: |
25+
Coda columnId of the column storing the CircleCI username in the CODA_USER_ROSTER_TABLE_URL document.
26+
type: string
27+
default: c-6ni4kHGNwE
28+
CODA_CIRCLECI_USER_ALIAS_COL:
29+
description: |
30+
Coda columnId of the column storing the user alias (when using EMAIL_DOMAIN), or fully qualified email.
31+
type: string
32+
default: c-26If9Zttyp
33+
EMAIL_DOMAIN:
34+
description: |
35+
Optional email domain for users within the workspace. Must be specified if user aliases are not fully qualified.
36+
type: string
37+
default: coda.io
38+
slack_bot_token:
39+
type: string
40+
description: |
41+
Token used by Slack bot application. Must have scopes `users:read`, `users:read.email`, and `chat:write`.
42+
default: ${PUSH_REMINDER_BOT_TOKEN}
43+
vcs:
44+
description: |
45+
Defaults to "gh", but allows other version control systems.
46+
type: string
47+
default: gh
48+
steps:
49+
- run:
50+
name: Fetch User Information from Look Up Table
51+
command: <<include(scripts/fetch_user_handles.sh)>>
52+
environment:
53+
SLACK_BOT_TOKEN: <<parameters.slack_bot_token>>
54+
CODA_API_TOKEN: <<parameters.coda_api_token>>
55+
CODA_CIRCLECI_USER_ALIAS_COL: <<parameters.CODA_CIRCLECI_USER_ALIAS_COL>>
56+
CODA_CIRCLECI_USER_NAME_COL: <<parameters.CODA_CIRCLECI_USER_NAME_COL>>
57+
CODA_USER_ROSTER_TABLE_URL: <<parameters.CODA_USER_ROSTER_TABLE_URL>>
58+
- when:
59+
condition: $SLACK_USER_ID
60+
steps:
61+
- run:
62+
name: Send Slack Message
63+
command: |
64+
set -eo pipefail
65+
curl -X POST -H "Authorization: Bearer $PUSH_REMINDER_BOT_TOKEN" \
66+
-H "Content-Type: application/json" -d \
67+
"{ \
68+
\"channel\": \"${SLACK_USER_ID}\", \
69+
\"attachments\": [ \
70+
{ \
71+
\"text\": \"Pending Approval for ${CIRCLE_PROJECT_REPONAME} (${CIRCLE_USERNAME})\", \
72+
\"fields\": [ \
73+
{ \
74+
\"title\": \"Project\", \
75+
\"value\": \"${CIRCLE_PROJECT_REPONAME}\", \
76+
\"short\": true \
77+
}, \
78+
{ \
79+
\"title\": \"Job Number\", \
80+
\"value\": \"${CIRCLE_BUILD_NUM}\", \
81+
\"short\": true \
82+
} \
83+
], \
84+
\"actions\": [ \
85+
{ \
86+
\"type\": \"button\", \
87+
\"text\": \"Visit Workflow\", \
88+
\"url\": \"https://circleci.com/workflow-run/${CIRCLE_WORKFLOW_ID}\" \
89+
} \
90+
], \
91+
\"color\": \"#f46a54\" \
92+
} \
93+
] \
94+
}" \
95+
'https://slack.com/api/chat.postMessage'

0 commit comments

Comments
 (0)