Skip to content

Commit 36236c6

Browse files
committed
Switch deployment to docker(-compose).
Builds a ~22MB docker image right now! Runs the CI tests in docker-compose, deploys with Heroku container support (deletes Procfile). Add docker-compose-based development flow.
1 parent f7d5f24 commit 36236c6

15 files changed

+740
-107
lines changed

.dockerignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*
2+
!src
3+
!Cargo.*
4+
!rfcbot.toml
5+
!rust-toolchain

.travis.yml

+16-28
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,31 @@ notifications:
44
addons:
55
apt:
66
packages:
7-
- libpq-dev
8-
- pkg-config
9-
- postgresql-11
10-
postgresql: "11.2"
7+
- libpq-dev
8+
- pkg-config
119
services:
12-
- postgresql
10+
- docker
1311
language: rust
14-
env: |
15-
DATABASE_POOL_SIZE=5 \
16-
DATABASE_URL=postgres:///rfcbot \
17-
GITHUB_SCRAPE_INTERVAL=6000 \
18-
GITHUB_USER_AGENT=rfcbot-rs \
19-
GITHUB_WEBHOOK_SECRETS=none \
20-
POST_COMMENTS=false \
21-
RUST_BACKTRACE=1 \
22-
RUST_LOG=error,rfcbot=debug
2312
before_install:
2413
- cargo fmt --all -- --check
2514
install:
26-
- sudo systemctl start postgresql
27-
- sudo -u postgres createuser --no-password --superuser $USER
28-
- cargo install diesel_cli --no-default-features --features postgres -Z install-upgrade
15+
- cargo install diesel_cli \
16+
--no-default-features --features postgres -Z install-upgrade
17+
- curl https://cli-assets.heroku.com/install-ubuntu.sh | sh
2918
before_script:
30-
- diesel setup
31-
- diesel migration run
32-
- psql -q -d "$DATABASE_URL" < githubuser-backup.pg
19+
- heroku container:login
20+
- heroku container:pull --app=rfcbot-rs web
3321
script:
34-
- export GITHUB_ACCESS_TOKEN="$GITHUB_ACCESS_TOKEN"
35-
- cargo build
36-
- cargo test
22+
- docker-compose up -d
23+
- ./setup-db.sh
24+
- docker-compose exec -e RUST_BACKTRACE=1 web cargo test --release --locked
25+
- heroku container:push --app=rfcbot-rs web
3726
before_deploy:
38-
- DATABASE_URL=$(heroku config:get DATABASE_URL -a rfcbot-rs) diesel migration run
27+
- DATABASE_URL=$(heroku config:get DATABASE_URL --app=rfcbot-rs) \
28+
diesel migration run
3929
deploy:
40-
provider: heroku
41-
skip_cleanup: true
42-
api_key:
43-
secure: "HgoF2n6pnzUhZ4oBNRo3gSoxj/o9x7QW0fKaj9sEYDNkTgak9IX3ha0antoYKB7dMw7IvB8oqVAHqldlGlG/kxUDKN8kaYA4O7CZgKP0auykTkmH61FP7MKV0hV0vyFfJLSraClVw/DL5tjYybs/rSBWFAvwttIB7QlcFv5sLIuwe5nHzftFfxba0H1+0oynO55FlmRzFBWydlFVNTsGVRddFHPgG3f2V9YYIjT18MKvn+BcV7WUq6QweB/3RjwTDYzws9mcWt6i3ju1D4nDTDVbtzeLs7Yt+NhnvrDeB+2FWSrV03LCjnnzv2zCUaROU522Vns0ZC/+2b9V3YbcCBJRA8QLBdo12JUCUzrdk8DOqIYKwlW6WbI3DcgRGz9Li7Dw2466+lsPidBfcdxnziTvc+r/2r6dKv3q7nwDpoZEyxnnTumPf50PJZs/lDu99Vo5C2NIdN2O5sqDHd8AJTLtWrY3FdN5MGKqTm0R9rVnObvUkTKbZJrDn39O5MU3mnHINUT+6ZCnNgra7rNn7Ai3tA1RKPB7kIZo41Td8j56iSLANXziCh0MikPfQv4x1scl3c1h5bR8ZqxVqH4IODjDJrJv43+hsbE9xGsmrC4OaqImLUpl/8zi6a4zZ8Na1AiFKVcdLZ9xt40/2yg7ysn53SCpQ5vty/j36clNwAE="
30+
provider: script
31+
script: heroku container:release --app=rfcbot-rs
4432
before_cache:
4533
# don't cache the cargo registry
4634
- rm -rf "$HOME/.cargo/registry"

CONTRIBUTING.md

+15-77
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,6 @@
44

55
Deployed to https://rfcbot.rs right now.
66

7-
## ToC
8-
9-
* [Development](#development)
10-
* [Configuring environment variables](#configuring-environment-variables)
11-
* [Running server processes](#running-server-processes)
12-
* [Database Connection](#database-connection)
13-
* [Configuration](#configuration)
14-
* [Rust Version](#rust-version)
15-
* [Environment variables](#environment-variables)
16-
* [Database](#database)
17-
* [Bootstrapping](#bootstrapping)
18-
* [Scraping](#scraping)
19-
* [Deployment](#deployment)
20-
* [Conduct](#conduct)
21-
* [License](#license)
22-
237
## Development
248

259
### Chat
@@ -28,84 +12,38 @@ There is an `#rfcbot` channel in the `ops` section of the [rust-lang discord ser
2812

2913
### Rust Version
3014

31-
Rust nightly is required, as rfcbot uses [Rocket](rocket.rs). If you use rustup, this version is controlled by a `rust-toolchain` file at the repository root.
32-
33-
### Heroku CLI
34-
35-
https://devcenter.heroku.com/articles/heroku-cli
36-
37-
### Environment variables
15+
Rust nightly is required, as rfcbot uses [Rocket](rocket.rs). If you use rustup, this version is managed for you by a `rust-toolchain` file at the repository root.
3816

39-
See config.rs for the environment variables expected. Also, rocket env vars are supported.
40-
41-
You can also create a [local `.env` file](https://github.com/dotenv-rs/dotenv#examples) which will
42-
be added to the environment variables the server sees.
43-
44-
### Database dumps
17+
### Running locally
4518

46-
It can be useful to have a database with some existing data to start from. "Bootstrap" files are available at https://www.dropbox.com/sh/dl4pxj1d49ici1f/AAAzZQxWVqQzVk_zOksn0Rbya?dl=0. They usually are behind several migrations, so you'll still need to run the migrations if you start from one.
47-
48-
See [below](#database) for information about restoring from a bootstrap file.
49-
50-
### Running server processes
51-
52-
There are two daemons to run, one for the front-end development server, and one for the back-end API server and scraper. It's recommended to run these in two separate terminal windows/tabs/sessions.
53-
54-
You may need to run database migrations if the bootstrap SQL file is stale:
55-
56-
```
57-
$ diesel migration run
58-
```
19+
Install [Docker](https://docker.dom) and [docker-compose](https://docs.docker.com/compose) and ensure they're working.
5920

60-
To run the back-end API server and scraper:
21+
Next, start development services and initialize the database:
6122

6223
```
63-
$ cargo run
24+
cargo install diesel_cli
25+
docker-compose up -d
26+
./setup-db.sh
6427
```
6528

66-
**NOTE:** The API server process needs to be manually restarted whenever you want to see code changes reflected in their behavior, or whenever you run migrations on the test database. A `Ctrl+C` followed by `Up` and `Enter` usually works if running them through cargo. `cargo watch` is also a nice tool.
67-
68-
### Database connection
69-
70-
If you want to perform any database action, make sure you have a reachable installation of PostgreSQL that is configured with the DATABASE_URL environment variable.
71-
72-
## Configuration
73-
74-
### Environment variables
75-
76-
Note that you can configure the Rocket web server using environment variables like `ROCKET_PORT`, according to the Rocket [configuration guide](https://rocket.rs/guide/configuration/).
29+
After this you may need to run `docker-compose down`/`docker-compose up -d` for the server process to see the database updates.
7730

78-
* `DATABASE_URL`: postgres database URL
79-
* `DATABASE_POOL_SIZE`: number of connections to maintain in the pool
80-
* `GITHUB_ACCESS_TOKEN`: your access token from GitHub. See [this page](https://help.github.com/articles/creating-an-access-token-for-command-line-use/) for more information. You shouldn't need to check any of the boxes for granting scopes when creating it.
81-
* `GITHUB_USER_AGENT`: the UA string to send to GitHub (they request that you send your GitHub username or the app name you registered for the client ID)
82-
* `GITHUB_WEBHOOK_SECRETS`: a comma-delimited string of the secrets used for any ingestion webhooks. The webhook handler will attempt to validate any POST'd webhook against each secret until it either finds a matching one or runs out.
83-
* `RUST_LOG`: the logging configuration for [env_logger](https://crates.io/crates/env_logger). If you're unfamiliar, you can read about it in the documentation linked on crates.io. If it's not defined, logging will default to `info!()` and above.
84-
* `GITHUB_SCRAPE_INTERVAL`: time (in minutes) to wait in between GitHub scrapes (scraping is disabled if this environment variable is omitted)
85-
* `POST_COMMENTS`: whether to post RFC bot comments on issues -- either `true` or `false`. Be very careful setting to true when testing -- it will post comments using whatever account is associated with the GitHub API key you provide.
31+
By default this stores your database files in `target/data/`, so any temporary changes you make to the database will be removed by a `cargo clean` and you'll need to run the above commands again.
8632

87-
## Database
88-
89-
To init, make sure `DATABASE_URL` is set and postgres is running, and:
90-
91-
```
92-
cargo install diesel_cli
93-
diesel setup
94-
diesel print-schema > src/domain/schema.rs
95-
```
33+
### Database dumps
9634

97-
If the database setup experiences errors, your user may not have permission to create databases or
98-
there may be other configuration problems.
35+
It can be useful to have a database with some existing data to start from. "Bootstrap" files are available at https://www.dropbox.com/sh/dl4pxj1d49ici1f/AAAzZQxWVqQzVk_zOksn0Rbya?dl=0.
9936

100-
That should have the database you've specified ready to receive data. Then you can run some of the bootstrapping commands (see below). Alternatively, you can use `bootstrap.sql` to get a nice starting point for the database (note that this isn't maintained regularly).
37+
Assuming that you download the most recent file in the above folder and name it `bootstrap.sql`:
10138

10239
```bash
103-
psql -d $DB_NAME_HERE -f bootstrap.sql
40+
# see setup-db.sh for the url to use here
41+
psql -d $DATABASE_URL -f bootstrap.sql
10442
```
10543

10644
## Deployment
10745

108-
Deployed to Heroku via TravisCI from the master branch.
46+
Deployed to Heroku via TravisCI from the master branch. See (.travis.yml)[./travis.yml] for an up-to-date listing of the actions.
10947

11048
## Conduct
11149

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ itertools = "0.8.0"
1313
lazy_static = "1.2.0"
1414
log = "0.4.6"
1515
maplit = "1.0.1"
16+
openssl = "*" # needs to be included for workaround from https://github.com/sgrif/pq-sys/issues/25
1617
reqwest = "0.9.12"
1718
rocket = "0.4.0"
1819
rocket_contrib = { version = "0.4.0", features = ["json", "handlebars_templates"] }

Dockerfile

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
###############################################################################
2+
# builder image
3+
4+
FROM clux/muslrust:stable as builder
5+
6+
WORKDIR /rfcbot
7+
RUN USER=root cargo init --vcs none
8+
9+
COPY rust-toolchain ./
10+
RUN rustc --version && rustup target add x86_64-unknown-linux-musl
11+
12+
COPY Cargo.toml Cargo.lock ./
13+
RUN cargo build --release
14+
15+
COPY . ./
16+
# cargo apparently uses mtime and docker doesn't modify it, needed to rebuild:
17+
RUN touch src/main.rs
18+
RUN cargo build --release --locked
19+
20+
###############################################################################
21+
# runner image
22+
23+
FROM alpine:latest
24+
RUN apk --no-cache add ca-certificates
25+
26+
# heroku runs as non-root
27+
RUN adduser -D notroot
28+
USER notroot
29+
30+
COPY --from=builder /rfcbot/target/x86_64-unknown-linux-musl/release/rfcbot-rs /usr/local/bin/rfcbot
31+
CMD ROCKET_PORT=$PORT /usr/local/bin/rfcbot

Procfile

-1
This file was deleted.

diesel.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[print_schema]
2-
file = "src/schema.rs"
2+
file = "src/domain/schema.rs"
33
with_docs = true

docker-compose.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
version: '3.4'
2+
services:
3+
web:
4+
build:
5+
context: .
6+
target: builder
7+
command: cargo run --release --locked
8+
depends_on:
9+
- db
10+
ports:
11+
- "9003:9003"
12+
environment:
13+
- DATABASE_POOL_SIZE=5
14+
- DATABASE_URL=postgres://postgres:ughfineokifitsfordebugging@db:5432/rfcbot
15+
- GITHUB_ACCESS_TOKEN=
16+
- GITHUB_SCRAPE_INTERVAL=6000
17+
- GITHUB_USER_AGENT=rfcbot-rs
18+
- GITHUB_WEBHOOK_SECRETS=none
19+
- POST_COMMENTS=false
20+
- ROCKET_ENV=dev
21+
- ROCKET_PORT=9003
22+
- RUST_BACKTRACE=1
23+
- RUST_LOG=error,rfcbot=debug
24+
db:
25+
image: "postgres:9"
26+
restart: always
27+
ports:
28+
- "54320:5432"
29+
environment:
30+
- POSTGRES_DB=rfcbot
31+
- POSTGRES_PASSWORD=ughfineokifitsfordebugging
32+
volumes:
33+
- ./target/data:/var/lib/postgresql/data
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- This file was automatically created by Diesel to setup helper functions
2+
-- and other internal bookkeeping. This file is safe to edit, any future
3+
-- changes will be added to existing projects as new migrations.
4+
5+
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
6+
DROP FUNCTION IF EXISTS diesel_set_updated_at();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- This file was automatically created by Diesel to setup helper functions
2+
-- and other internal bookkeeping. This file is safe to edit, any future
3+
-- changes will be added to existing projects as new migrations.
4+
5+
6+
7+
8+
-- Sets up a trigger for the given table to automatically set a column called
9+
-- `updated_at` whenever the row is modified (unless `updated_at` was included
10+
-- in the modified columns)
11+
--
12+
-- # Example
13+
--
14+
-- ```sql
15+
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
16+
--
17+
-- SELECT diesel_manage_updated_at('users');
18+
-- ```
19+
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
20+
BEGIN
21+
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
22+
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
23+
END;
24+
$$ LANGUAGE plpgsql;
25+
26+
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
27+
BEGIN
28+
IF (
29+
NEW IS DISTINCT FROM OLD AND
30+
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
31+
) THEN
32+
NEW.updated_at := current_timestamp;
33+
END IF;
34+
RETURN NEW;
35+
END;
36+
$$ LANGUAGE plpgsql;

setup-db.sh

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
set -xe
4+
5+
export DATABASE_URL="postgres://postgres:ughfineokifitsfordebugging@localhost:54320/rfcbot"
6+
7+
until psql -d "$DATABASE_URL" -c '\q'; do
8+
>&2 echo "Postgres is unavailable - sleeping"
9+
sleep 1
10+
done
11+
12+
>&2 echo "Postgres is up - executing commands"
13+
14+
diesel database setup
15+
diesel migration run
16+
psql -q -d "$DATABASE_URL" --file ./githubuser-backup.pg

src/config.rs

+27
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).
2+
//! Configuration environment variables for rfcbot.
3+
//!
4+
//! Note that you can configure the Rocket web server using environment variables like
5+
//! `ROCKET_PORT`, according to the Rocket
6+
//! [configuration guide](https://rocket.rs/guide/configuration/).
7+
//!
8+
//! Here are the variables rfcbot expects to see in its environment:
9+
//!
10+
//! * `DATABASE_URL`: postgres database URL
11+
//! * `DATABASE_POOL_SIZE`: number of connections to maintain in the pool
12+
//! * `GITHUB_ACCESS_TOKEN`: your access token from GitHub. See
13+
//! [this page](https://help.github.com/articles/creating-an-access-token-for-command-line-use/)
14+
//! for more information. You shouldn't need to check any of the boxes for granting scopes when
15+
//! creating it.
16+
//! * `GITHUB_USER_AGENT`: the UA string to send to GitHub (they request that you send your GitHub
17+
//! username or the app name you registered for the client ID)
18+
//! * `GITHUB_WEBHOOK_SECRETS`: a comma-delimited string of the secrets used for any ingestion
19+
//! webhooks. The webhook handler will attempt to validate any POST'd webhook against each secret
20+
//! until it either finds a matching one or runs out.
21+
//! * `RUST_LOG`: the logging configuration for [env_logger](https://crates.io/crates/env_logger).
22+
//! If you're unfamiliar, you can read about it in the documentation linked on crates.io. If it's
23+
//! not defined, logging will default to `info!()` and above.
24+
//! * `GITHUB_SCRAPE_INTERVAL`: time (in minutes) to wait in between GitHub scrapes (scraping is
25+
//! disabled if this environment variable is omitted)
26+
//! * `POST_COMMENTS`: whether to post RFC bot comments on issues -- either `true` or `false`. Be
27+
//! very careful setting to true when testing -- it will post comments using whatever account is
28+
//! associated with the GitHub API key you provide.
229
330
use std::collections::BTreeMap;
431
use std::env;

0 commit comments

Comments
 (0)