Skip to content

Commit bf5f803

Browse files
committed
introduce epicast development guide
- includes detailed instructions for local development, checking code into the `dev` branch, and cherry-picking code over to the `prod` branch - the guide lives in the `master` branch since it is about the development process in general, and is not specific to the the `dev` branch
1 parent 1cc50b2 commit bf5f803

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@ Friday through Monday), except in case of a critical bugfix.
3838
In any case, all code commits to `prod` should only consist of merges from
3939
`dev`, rather than direct commits. (An exception to this is configuration,
4040
which differs between environments.)
41+
42+
# Development
43+
44+
For developing the website, see the
45+
[epicast development guide](docs/epicast_development.md).

docs/epicast_development.md

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
# Epicast Website Development Guide
2+
3+
**Prerequisite:** this guide assumes that you have read the
4+
[frontend development guide](https://github.com/cmu-delphi/operations/blob/master/docs/frontend_development.md).
5+
6+
This guide describes how run a local development instance of the Epicast
7+
website. For preliminary steps,
8+
[install docker and create a virtual network](https://github.com/cmu-delphi/operations/blob/master/docs/frontend_development.md#setup).
9+
10+
# setup
11+
12+
For working on the Epicast website, you'll need the following two Delphi
13+
repositories:
14+
15+
- [operations](https://github.com/cmu-delphi/operations)
16+
- [www-epicast](https://github.com/cmu-delphi/www-epicast)
17+
18+
You likely won't need to modify the `operations` repo, so cloning directly from
19+
`cmu-delphi` is usually sufficient. However, since you _are_ going to be
20+
modifying `www-epicast` sources, you'll first need to fork the repository
21+
and then clone your personal fork. For more details, see the Delphi-specific
22+
[discussion on forking and branching](https://github.com/cmu-delphi/operations/blob/master/docs/backend_development.md#everyone).
23+
24+
Here's an example of how to setup your local workspace. Note that you will need
25+
to use your own GitHub username where indicated.
26+
27+
```bash
28+
# collect everything in a directory called "repos"
29+
mkdir repos && cd repos
30+
31+
# delphi python (sub)packages
32+
mkdir delphi && cd delphi
33+
git clone https://github.com/cmu-delphi/operations
34+
git clone https://github.com/Your-GitHub-Username/www-epicast
35+
cd ..
36+
37+
# go back up to the workspace root
38+
cd ..
39+
```
40+
41+
Your workspace should now look like this:
42+
43+
```bash
44+
tree -L 3 .
45+
```
46+
47+
```
48+
.
49+
└── repos
50+
└── delphi
51+
├── operations
52+
└── www-epicast
53+
```
54+
55+
# branches and deployment
56+
57+
Note that Epicast follows a weekly release cadence whereby select changes in
58+
the `dev` branch are
59+
[cherry-picked](https://www.atlassian.com/git/tutorials/cherry-pick)
60+
into the `prod` branch. The `prod` branch should never be committed to
61+
directly, and changes shouldn't be merged in from `dev` during active
62+
forecasting, which is nominally Friday through Monday each week.
63+
64+
The `HEAD` of the `dev` branch is continuously deployed to a staging server
65+
which, with credentials, you can access at
66+
https://app-mono-dev-01.delphi.cmu.edu/cc-test. Similarly, the `HEAD` of the
67+
`prod` branch is continuously deployed to the production server which is
68+
publicly accessible at https://delphi.cmu.edu/crowdcast/.
69+
70+
For additional details about the various branches, and the intended use-cases
71+
of each, see [the top-level readme](../README.md). Notably, the `master` branch
72+
has only documentation and not code. This is because documentation (e.g. this
73+
guide) is generally not specific to any particular branch, whereas the master
74+
branch has intentionally undefined deployment semantics and should not contain
75+
any code.
76+
77+
# build images
78+
79+
For the purposes of this guide, which is broadly focused on the typical Epicast
80+
development workflow, go ahead and checkout the `dev` branch which is where the
81+
development version of the code lives. We will return to the `prod` branch
82+
later in this guide.
83+
84+
```bash
85+
git \
86+
--git-dir repos/delphi/www-epicast/.git \
87+
--work-tree repos/delphi/www-epicast \
88+
checkout dev
89+
```
90+
91+
We now need images for the Epicast web server and database. These are both
92+
based on core Delphi images which are defined in the
93+
[`operations` repo](https://github.com/cmu-delphi/operations) which you cloned
94+
above. The base images are built first, followed by the derived
95+
`epicast`-specific images.
96+
97+
- The [`delphi_web_epicast` image](../dev/docker/web/epicast/README.md) adds
98+
the Epicast website to the `delphi_web` image.
99+
- The
100+
[`delphi_database_epicast` image](../dev/docker/database/epicast/README.md)
101+
adds the `epi` user account, `epicast2` (legacy name) database, and relevant
102+
tables to the `delphi_database` image.
103+
104+
From the root of your workspace, all of the images can be built as follows.
105+
**Be sure to have checked out an appropriate branch as described above, as
106+
branch `master` doesn't contain the requisite files.**
107+
108+
```bash
109+
docker build -t delphi_web \
110+
-f repos/delphi/operations/dev/docker/web/Dockerfile .
111+
112+
docker build -t delphi_web_epicast \
113+
-f repos/delphi/www-epicast/dev/docker/web/epicast/Dockerfile .
114+
115+
docker build -t delphi_database \
116+
-f repos/delphi/operations/dev/docker/database/Dockerfile .
117+
118+
docker build -t delphi_database_epicast \
119+
-f repos/delphi/www-epicast/dev/docker/database/epicast/Dockerfile .
120+
```
121+
122+
# develop
123+
124+
At this point you're ready to bring the stack online. To do that, just start
125+
containers for the Epicast-specific web and database images. As an aside, the
126+
output from these commands (especially the web server) can be very helpful for
127+
debugging. For example, in separate terminals:
128+
129+
```bash
130+
# launch the database
131+
docker run --rm -p 13306:3306 \
132+
--network delphi-net --name delphi_database_epicast \
133+
delphi_database_epicast
134+
135+
# launch the web server
136+
docker run --rm -p 10080:80 \
137+
--network delphi-net --name delphi_web_epicast \
138+
delphi_web_epicast
139+
```
140+
141+
You should now be able to visit your own personal instance of the website,
142+
backed by your own personal instance of the database, by visiting
143+
http://localhost:10080/ in a web browser. Note that your user ID for login is
144+
"00000000", as defined in `src/ddl/development_data.sql` (see the line like
145+
`INSERT INTO ``ec_fluv_users`` ... `).
146+
147+
After making website changes, bring the `delphi_web_epicast` container down
148+
(e.g. `docker stop delphi_web_epicast`), rebuild the image, and relaunch the
149+
container. This stop-build-start cycle is necessary to pick up modifications to
150+
your local source files. This is good for the sake of bundling and running a
151+
self-contained and isolated unit of code, but it's suboptimal in terms of rapid
152+
iteration and developer experience.
153+
154+
It's possible to [bind-mount](https://docs.docker.com/storage/bind-mounts/) a
155+
local directory (say `repos/delphi/www-epicast/site/`) to a directory in a
156+
container. This opens up your local filesystem to the container, which is not
157+
normally granted such visibility. By doing it this way, local changes to source
158+
files are immediately visible (subject to page refresh and caching, etc) in
159+
your local instance of the website. The huge benefit of doing it this way is
160+
that you don't have to stop, rebuild, and restart every time you want to test
161+
out a code change. However, there are some drawbacks to keep in mind:
162+
163+
- your local filesystem is now exposed to code running in the container (this
164+
isn't much of a practical concern in this case since we generally trust the
165+
code written by fellow Delphi developers, but still something to be aware of)
166+
- this is very tedious to specify on the command line, and changes to directory
167+
structure can cause the mount flag to no longer work
168+
- several mount flags, each of which is tedious, may be needed, depending on
169+
how the code in the repo maps to code on the server (i.e. must replicate the
170+
mapping defined in `deploy.json`)
171+
172+
Here's an example of how to bind-mount the website source files in your local
173+
`www-epicast` repository into a `delphi_web_epicast` container:
174+
175+
```bash
176+
# launch the web server, serving website files from your actual filesystem
177+
# rather than from the image
178+
docker run --rm -p 10080:80 \
179+
--mount type=bind,source="$(pwd)"/repos/delphi/www-epicast/site,target=/var/www/html,readonly \
180+
--mount type=bind,source="$(pwd)"/repos/delphi/www-epicast/dev/docker/web/epicast/assets/settings.php,target=/var/www/html/common/settings.php,readonly \
181+
--network delphi-net --name delphi_web_epicast \
182+
delphi_web_epicast
183+
```
184+
185+
When development is finished, it's a good idea to test things out one final
186+
time _without_ bind-mounting. This helps to ensure that all the code is working
187+
as intended without depending on changes to other bind-mounted local files
188+
which haven't captured by the image.
189+
190+
# updating `prod`
191+
192+
[Cherry-picking](https://www.atlassian.com/git/tutorials/cherry-pick) is the
193+
process by which specific commits are taken from the `dev` branch and copied
194+
over to the `prod` branch. Aside from production-specific configuration
195+
changes, this is the only way by which code changes should be introduced to the
196+
`prod` branch.
197+
198+
To begin, suppose there has been some sequence of commits made to the `dev`
199+
branch, one of which we now want to port over to the `prod` branch. This can be
200+
done from the root of your workspace, but for simplicity, change directory into
201+
the `www-epicast` repo. Then, identify the commit by its hash, which can
202+
determined by `git log`, for example:
203+
204+
```bash
205+
# move into the repo to simplify subsequent git commands
206+
cd repos/delphi/www-epicast
207+
208+
# checkout the dev branch
209+
git checkout dev
210+
211+
# show recent commits
212+
git log --oneline | head -5
213+
```
214+
215+
```
216+
965682a database ddl and local docker development
217+
be9867e grant access during local docker development
218+
6f3f719 remove unused css-as-php files
219+
b61eb03 update advanced preferences, fixes #12
220+
a27efc0 get latest issue from epidata api
221+
```
222+
223+
Let's assume that we want to bring over the changes from "update advanced
224+
preferences, fixes #12", with commit hash `b61eb03`.
225+
226+
Switch over to the `prod` branch, and make the cherry-pick:
227+
228+
```bash
229+
# checkout the prod branch
230+
git checkout prod
231+
232+
# cherry-pick the bugfix
233+
git cherry-pick b61eb03
234+
```
235+
236+
```
237+
[prod f64268b] update advanced preferences, fixes #12
238+
Date: Tue Apr 28 15:05:18 2020 -0500
239+
1 file changed, 4 insertions(+), 4 deletions(-)
240+
```
241+
242+
You can confirm that the commit was cherry-picked into `prod` by `git log`.
243+
244+
In case of merge conflicts, you will see a message similar to the following:
245+
246+
```
247+
error: could not apply d43ef45... remove the caching service worker
248+
hint: after resolving the conflicts, mark the corrected paths
249+
hint: with 'git add <paths>' or 'git rm <paths>'
250+
hint: and commit the result with 'git commit'
251+
```
252+
253+
In this case, you'll have to manually resolve the merge conflict (use `git
254+
status` to find the modified but unstaged file), add the resolved file(s), and
255+
then finish up with `git commit`.
256+
257+
Finally, submit a pull request against the `prod` branch of the `www-epicast`
258+
repo, where after quick sanity check review, the changes can be merged into the
259+
`prod` branch and subsequently automatically deployed to the production
260+
environment.

0 commit comments

Comments
 (0)