Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit 094d1f5

Browse files
Merge pull request #71 from ShorensteinCenter/devel
[Feature, N/A] Add Codecov and CircleCI Badges
2 parents 82816d7 + f638175 commit 094d1f5

2 files changed

Lines changed: 164 additions & 162 deletions

File tree

.circleci/configure_orca.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

README.md

Lines changed: 164 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,164 @@
1-
# Shorenstein Center Email Benchmarks
2-
3-
This is a tool developed by the Shorenstein Center at the Harvard Kennedy School to import MailChimp email list data, analyze it, and output the resulting metrics in an email report.
4-
5-
## Getting Started
6-
7-
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
8-
9-
### Prerequisites
10-
11-
* [Python](https://www.python.org), version 3.5+ (3.6+ recommended).
12-
* [RabbitMQ](https://www.rabbitmq.com/) or another AMQP broker.
13-
* A relational database, e.g. [SQLite](https://www.sqlite.org) or [PostgreSQL](https://www.postgresql.org/).
14-
* [NodeJS](https://nodejs.org). We're currently using version 11.2, but any recent version should work. (We use [NVM](https://github.com/creationix/nvm) to manage Node versions.)
15-
* [Amazon SES](https://aws.amazon.com/ses/) (optional, see below).
16-
17-
### Local Development
18-
19-
##### Create a new virtual environment
20-
21-
virtualenv venv
22-
source venv/bin/activate
23-
24-
##### Install Python dependencies
25-
26-
pip install -r requirements.txt
27-
28-
##### Set environment variables
29-
30-
* `SECRET_KEY` - Flask secret key.
31-
* `CELERY_BROKER_URI` - The URI of the Celery broker. Default `'amqp://guest:guest@localhost:5672/'` (a broker running locally on port `5672`).
32-
* `SQLALCHEMY_DATABASE_URI` - The URI of the database. Default is a `sqlite` database named `app.db` located at the application root.
33-
* `SERVER_NAME` - the URL for the app. Default `127.0.0.1:5000` (suitable for running locally). Note that the URLs for assets sent via email (images, etc.) are generated using Flask's `url_for()` function. If `SERVER_NAME` is not externally accessible these assets will not send succesfully.
34-
* `NO_PROXY` - We use proxies to distribute our MailChimp requests across IP addresses. Set this variable to `True` in order to disable proxying, or modify the `enable_proxy` method in `app/lists.py` according to your proxy configuration.
35-
* `NO_EMAIL` - If set, suppresses sending of email reports (as well as error emails, etc.).
36-
37-
If `NO_EMAIL` is not set, Amazon SES is required along with the following variables:
38-
39-
* `AWS_ACCESS_KEY_ID` - AWS Access Key ID for the API.
40-
* `AWS_SECRET_ACCESS_KEY` - AWS Secret Access Key for the API.
41-
* `SES_REGION_NAME` - AWS Simple Email Service region. Default `us-west-2`.
42-
* `SES_DEFAULT_EMAIL_SOURCE` - The default email address to send from. This email needs to be verified by SES and active outside the SES sandbox.
43-
* `ADMIN_EMAIL` - Email address to send error emails to. Optional.
44-
* `SES_CONFIGURATION_SET` - SES Configuration Set for tracking opens/clicks/etc. Optional.
45-
46-
The following variables are only required to run integration tests:
47-
48-
* `TESTING_API_KEY` - MailChimp API key to use in integration tests.
49-
* `TESTING_LIST_ID` - MailChimp list ID to run integration tests against.
50-
51-
##### Upgrade the database
52-
53-
export FLASK_APP=app.py
54-
flask db upgrade
55-
56-
##### Install Node dependencies
57-
58-
npm install
59-
60-
You may need to add the installed binaries to your system path (or install with the `-g` flag), as the application expects to find certain executables (such as `orca`).
61-
62-
##### Compile front-end
63-
64-
npm run gulp
65-
66-
##### Run the application
67-
68-
flask run
69-
70-
##### Run Celery
71-
72-
celery worker -A app.celery --loglevel=INFO
73-
74-
Finally, open a web browser and navigate to the `SERVER_NAME` URI.
75-
76-
## Testing
77-
78-
Run unit and integration tests with `pytest`:
79-
80-
python -m pytest tests/unit
81-
python -m pytest tests/integration
82-
83-
To generate a coverage report as well:
84-
85-
python -m pytest --cov=app --cov-report term-missing tests/unit
86-
87-
## Linting
88-
89-
Lint the backend with `pylint`:
90-
91-
pylint app
92-
93-
Lint the frontend:
94-
95-
npm run lint
96-
97-
Python and Javascript rules are defined in `pylintrc` and `.eslintrc`, respectively.
98-
99-
## Deployment
100-
101-
This app is environment-agnostic. We deployed it on Ubuntu using `gunicorn` and `nginx`, and daemonized `Celery` and `Celery Beat`. Here are a few pointers on what we did.
102-
103-
A sample init script for gunicorn:
104-
105-
[Unit]
106-
Description=Gunicorn instance to serve app
107-
After=network.target
108-
109-
[Service]
110-
User=app_user
111-
Group=www-data
112-
WorkingDirectory=/path/to/app
113-
Environment="PATH=/path/to/app/venv/bin"
114-
ExecStart=/path/to/app/venv/bin/gunicorn --workers 5 --bind unix:email-benchmarks.sock -m 007 app:app
115-
116-
[Install]
117-
WantedBy=multi-user.target
118-
119-
A sample init script for nginx:
120-
121-
server {
122-
listen 80;
123-
server_name SERVER_NAME;
124-
125-
location / {
126-
include proxy_params;
127-
proxy_pass http://unix:/path/to/app/email-benchmarks.sock;
128-
}
129-
}
130-
131-
Sample init scripts for `Celery` can be found in the [Celery repo](https://github.com/celery/celery/tree/master/extra/generic-init.d/).
132-
133-
Setting up [Orca](https://github.com/plotly/orca) (required for exporting visualizations from Plotly) can be tricky on headless machines. We got it to work by installing the standalone binaries and additional dependencies (such as `google-chrome-stable`) as per the `readme`, then using Xvfb with the `-a` flag, i.e. `xvfb-run -a ...`. Additionally, restarting a daemonized Celery will create a new xvfb instance rather than re-using the one that is already running. We added the following function to our Celery init script, which kills running xvfb processes:
134-
135-
kill_xvfb () {
136-
local xvfb_pids=`ps aux | grep tmp/xvfb-run | grep -v grep | awk '{print $2}'`
137-
if [ "$xvfb_pids" != "" ]; then
138-
echo "Killing the following xvfb processes: $xvfb_pids"
139-
sudo kill $xvfb_pids
140-
else
141-
echo "No xvfb processes to kill"
142-
fi
143-
}
144-
145-
## Authors
146-
147-
* **William Hakim** - [William Hakim](https://github.com/williamhakim10)
148-
149-
## Acknowledgements
150-
151-
This project is generously supported by the [Knight Foundation](https://knightfoundation.org/).
152-
153-
We use [Browserstack](https://www.browserstack.com/) to help ensure our projects work across platforms and devices.
154-
155-
## License
156-
157-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
1+
# Shorenstein Center Email Benchmarks
2+
3+
This is a tool developed by the Shorenstein Center at the Harvard Kennedy School to import MailChimp email list data, analyze it, and output the resulting metrics in an email report.
4+
5+
## Branches
6+
7+
| Branch | Tests | Code Coverage | Comments |
8+
| ------ | ----- | ------------- | -------- |
9+
| `devel` | [![CircleCI](https://circleci.com/gh/ShorensteinCenter/Benchmarks-Program/tree/devel.svg?style=svg)](https://circleci.com/gh/ShorensteinCenter/Benchmarks-Program/tree/devel) | [![codecov](https://codecov.io/gh/ShorensteinCenter/Benchmarks-Program/branch/devel/graph/badge.svg)](https://codecov.io/gh/ShorensteinCenter/Benchmarks-Program) | Current work in progress |
10+
| `master` | [![CircleCI](https://circleci.com/gh/ShorensteinCenter/Benchmarks-Program.svg?style=svg)](https://circleci.com/gh/ShorensteinCenter/Benchmarks-Program) | [![codecov](https://codecov.io/gh/ShorensteinCenter/Benchmarks-Program/branch/master/graph/badge.svg)](https://codecov.io/gh/ShorensteinCenter/Benchmarks-Program) | Latest official release |
11+
12+
## Getting Started
13+
14+
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
15+
16+
### Prerequisites
17+
18+
* [Python](https://www.python.org), version 3.5+ (3.6+ recommended).
19+
* [RabbitMQ](https://www.rabbitmq.com/) or another AMQP broker.
20+
* A relational database, e.g. [SQLite](https://www.sqlite.org) or [PostgreSQL](https://www.postgresql.org/).
21+
* [NodeJS](https://nodejs.org). We're currently using version 11.2, but any recent version should work. (We use [NVM](https://github.com/creationix/nvm) to manage Node versions.)
22+
* [Amazon SES](https://aws.amazon.com/ses/) (optional, see below).
23+
24+
### Local Development
25+
26+
##### Create a new virtual environment
27+
28+
virtualenv venv
29+
source venv/bin/activate
30+
31+
##### Install Python dependencies
32+
33+
pip install -r requirements.txt
34+
35+
##### Set environment variables
36+
37+
* `SECRET_KEY` - Flask secret key.
38+
* `CELERY_BROKER_URI` - The URI of the Celery broker. Default `'amqp://guest:guest@localhost:5672/'` (a broker running locally on port `5672`).
39+
* `SQLALCHEMY_DATABASE_URI` - The URI of the database. Default is a `sqlite` database named `app.db` located at the application root.
40+
* `SERVER_NAME` - the URL for the app. Default `127.0.0.1:5000` (suitable for running locally). Note that the URLs for assets sent via email (images, etc.) are generated using Flask's `url_for()` function. If `SERVER_NAME` is not externally accessible these assets will not send succesfully.
41+
* `NO_PROXY` - We use proxies to distribute our MailChimp requests across IP addresses. Set this variable to `True` in order to disable proxying, or modify the `enable_proxy` method in `app/lists.py` according to your proxy configuration.
42+
* `NO_EMAIL` - If set, suppresses sending of email reports (as well as error emails, etc.).
43+
44+
If `NO_EMAIL` is not set, Amazon SES is required along with the following variables:
45+
46+
* `AWS_ACCESS_KEY_ID` - AWS Access Key ID for the API.
47+
* `AWS_SECRET_ACCESS_KEY` - AWS Secret Access Key for the API.
48+
* `SES_REGION_NAME` - AWS Simple Email Service region. Default `us-west-2`.
49+
* `SES_DEFAULT_EMAIL_SOURCE` - The default email address to send from. This email needs to be verified by SES and active outside the SES sandbox.
50+
* `ADMIN_EMAIL` - Email address to send error emails to. Optional.
51+
* `SES_CONFIGURATION_SET` - SES Configuration Set for tracking opens/clicks/etc. Optional.
52+
53+
The following variables are only required to run integration tests:
54+
55+
* `TESTING_API_KEY` - MailChimp API key to use in integration tests.
56+
* `TESTING_LIST_ID` - MailChimp list ID to run integration tests against.
57+
58+
##### Upgrade the database
59+
60+
export FLASK_APP=app.py
61+
flask db upgrade
62+
63+
##### Install Node dependencies
64+
65+
npm install
66+
67+
You may need to add the installed binaries to your system path (or install with the `-g` flag), as the application expects to find certain executables (such as `orca`).
68+
69+
##### Compile front-end
70+
71+
npm run gulp
72+
73+
##### Run the application
74+
75+
flask run
76+
77+
##### Run Celery
78+
79+
celery worker -A app.celery --loglevel=INFO
80+
81+
Finally, open a web browser and navigate to the `SERVER_NAME` URI.
82+
83+
## Testing
84+
85+
Run unit and integration tests with `pytest`:
86+
87+
python -m pytest tests/unit
88+
python -m pytest tests/integration
89+
90+
To generate a coverage report as well:
91+
92+
python -m pytest --cov=app --cov-report term-missing tests/unit
93+
94+
## Linting
95+
96+
Lint the backend with `pylint`:
97+
98+
pylint app
99+
100+
Lint the frontend:
101+
102+
npm run lint
103+
104+
Python and Javascript rules are defined in `pylintrc` and `.eslintrc`, respectively.
105+
106+
## Deployment
107+
108+
This app is environment-agnostic. We deployed it on Ubuntu using `gunicorn` and `nginx`, and daemonized `Celery` and `Celery Beat`. Here are a few pointers on what we did.
109+
110+
A sample init script for gunicorn:
111+
112+
[Unit]
113+
Description=Gunicorn instance to serve app
114+
After=network.target
115+
116+
[Service]
117+
User=app_user
118+
Group=www-data
119+
WorkingDirectory=/path/to/app
120+
Environment="PATH=/path/to/app/venv/bin"
121+
ExecStart=/path/to/app/venv/bin/gunicorn --workers 5 --bind unix:email-benchmarks.sock -m 007 app:app
122+
123+
[Install]
124+
WantedBy=multi-user.target
125+
126+
A sample init script for nginx:
127+
128+
server {
129+
listen 80;
130+
server_name SERVER_NAME;
131+
132+
location / {
133+
include proxy_params;
134+
proxy_pass http://unix:/path/to/app/email-benchmarks.sock;
135+
}
136+
}
137+
138+
Sample init scripts for `Celery` can be found in the [Celery repo](https://github.com/celery/celery/tree/master/extra/generic-init.d/).
139+
140+
Setting up [Orca](https://github.com/plotly/orca) (required for exporting visualizations from Plotly) can be tricky on headless machines. We got it to work by installing the standalone binaries and additional dependencies (such as `google-chrome-stable`) as per the `readme`, then using Xvfb with the `-a` flag, i.e. `xvfb-run -a ...`. Additionally, restarting a daemonized Celery will create a new xvfb instance rather than re-using the one that is already running. We added the following function to our Celery init script, which kills running xvfb processes:
141+
142+
kill_xvfb () {
143+
local xvfb_pids=`ps aux | grep tmp/xvfb-run | grep -v grep | awk '{print $2}'`
144+
if [ "$xvfb_pids" != "" ]; then
145+
echo "Killing the following xvfb processes: $xvfb_pids"
146+
sudo kill $xvfb_pids
147+
else
148+
echo "No xvfb processes to kill"
149+
fi
150+
}
151+
152+
## Authors
153+
154+
* **William Hakim** - [William Hakim](https://github.com/williamhakim10)
155+
156+
## Acknowledgements
157+
158+
This project is generously supported by the [Knight Foundation](https://knightfoundation.org/).
159+
160+
We use [Browserstack](https://www.browserstack.com/) to help ensure our projects work across platforms and devices.
161+
162+
## License
163+
164+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details

0 commit comments

Comments
 (0)