Skip to main content

DevOps

With all the pieces of the application at hand we are ready to lay out CI/CD pipeline architecture.

Pipeline

Hosting

For the simplicity of usage and zero payment service, we are using github static hosting. According to the service, we need to specify a branch that will hold compiled application. The rest is taking care of for us (excluding custom domain, more on this later). Since master branch is already used by the application source code itself, we can use a second option - gh-pages branch.

Deployment

Manually deployment process looks simple.

  1. Data files are downloaded from the public data source
  2. Data files are saved into the public folder
  3. The application is built into the build folder that is excluded from source control tracking
  4. Application source code is cloned into a separate folder from remote (gh-pages branch only)
  5. public folder content from original application source folder is copied to the new clone
  6. Commit and push of the gh-page branch to remote is executed

Unfortunately this process would work only once. Next time, when we execute the same sequence of steps, previously saved data source would be overridden. At the second step, when we save downloaded data to the public folder, we are not taking care of previously saved information.

So the new/fixed process looks like this:

  1. Download data files
  2. Download previously saved data files (from github using raw.githubusercontent.com server)
  3. Merge new data files into old data files
  4. Save merged data into the public folder
  5. Build the application
  6. Clone gh-pages branch from remote
  7. Copy public folder contents into gh-pages clone
  8. Commit and push

Actions

Besides the hosting, github will help us automating the deployment process as well. It provides a feature that does exactly what we are looking for - automate the workflow described by deployment steps. This feature is called actions and is turned on automatically when repository source code contains specific execution script with all the steps.

It is possible to automate all the steps we need as is, but for the gh-pages branch deployment we are going to use an existing step built by somebody else (there is no need to reinvent the wheel). Different actions could be imported into the workflow from different repositories for the purpose of reusability. We we are taking advantage of this options as well.

Here is how our actions look in the workflow:

Checkout sources code

Checking out source code is a built-in action, we just need to use it

- uses: actions/checkout@v2

Setup nodejs environment

Nodejs step is also built-in but requires extra config to specify exact version of node to be used

strategy:
matrix:
node-version: [14.x]

...

- name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

Load data

Next one is a custom action and represents JavaScript file that is executed for a particular step. In our case, it's a file that is part of the source control. It loads, merges and saves data.

- uses: ./.github/actions/load-data

Install dependencies

After data is saved, we have to prepare the source code for the compilation by installing necessary 3rd party dependencies.

- name: Install
run: npm ci

Build

While building the application we need to provide all the environment variables required. Variables that should not be exposed to public are taken from github secrets.

- name: Build
run: npm run build --if-present
env:
REACT_APP_MAP_TOKEN: ${{ secrets.MAPBOX_KEY }}
REACT_APP_DATA_URL: .
REACT_APP_GITHUB_URL: https://github.com/maxgherman/nsw-coronavirus

Deploy

Deployment itself represents an invocation of the action we exported into the workflow before

- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
deploy_key: ${{ secrets.GH_PAGES_DEPLOY_KEY }}
publish_dir: ./build
publish_branch: gh-pages
cname: nsw-coronavirus.js.org

Custom domain

By default, github hosting provides publishing under github.io domain. Final URL includes username and repository name

Github histing URL for user repositories: http(s):// user .github.io/ repository

Specifying a custom domain requires a few more details. As you might noticed, previous step has one of the parameters called cname. This parameter instructs the step action to create a file called CNAME at the root of the repo with one single line nsw-coronavirus.js.org. Essentially, this file represents a CNAME record that links one DNS entry to another in a way that requests to nsw-coronavirus.js.org are resolved by http(s):// user .github.io/repository. Finally, we need to instruct js.org DNS servers of the linking between js.org and github.io. There is a project that does just that for free. The only thing we need is to create a pull request following provided instructions.

References

Github static hosting

Github actions

Deploy to gh-pages action

Github secrets

github.io domain

CNAME record

js.org hosting