Backstage Frontend
Backstage Frontend is a React-redux, redux-observalbe web client for the CNE Backstage workflow managment application. Click here for Application Architecture details.
Pre-requisites
CNE Dev Environment Setup
Follow the links below for installation instructions:
Required Git Repositories
git clone git@github.com:cnerepo/backstage-frontend.git
git clone git@github.com:cnerepo/backstage-api.git
git clone git@github.com:cnerepo/cne-dockerfiles.git
git clone git@github.com:cnerepo/documentation.git
Node & Node Dependencies
Install the latest stable node version.
nvm install
Install Node dependencies for the frontend and API apps
cd backstage-frontend
npm install
cd ../backstage-api
npm install
Link the backstage-utils package to both backstage-api and backstage-frontend. This will ensure that any changes made to backstage-utils will be automatically reflected in backstage-api's node modules without re-installing the dependency.
cd /backsage-api/src/backstage-utils
npm link # create a global link
cd /backstage-api
npm link @condenast/backstage-utils # link-install backstage-utils in backstage-api
# Repeat these steps for backstage-frontend...
MongoDB Installation
brew tap mongodb/brew
brew install mongodb-community@4.0
Local Development
Start up local DBs in Docker
If you haven't already, clone the cne-dockerfiles repo.
Use docker-compose to start up the backstage DB (mongo 4.0) in docker and other servers required for other apps:
cd ../cne-dockerfiles/databases-dev
docker-compose up -d
docker ps
Verify the last command, docker ps
(process status), lists these containers:
CONTAINER ID IMAGE PORTS
f340fb27a1f1 databases-dev_mongodb40:latest 0.0.0.0:27018->27017/tcp
e52ba463d407 databases-dev_mongodb:latest 0.0.0.0:27017->27017/tcp
84190bcb0344 databases-dev_redis:latest 0.0.0.0:6379->6379/tcp
Restore production data
You can periodically refresh your local Backstage DB with production data by restoring the latest backup from S3. The restore script lives in the documentation
repo.
The following environment variables are required by the restore script
export BACKSTAGE_DB_PORT=27018
export CNE_DB_IP=localhost
And to restore production data to your local db:
cd ../documentation
./scripts/restore-backstage-dev.sh
Restoring production data to a non-local environment is a little less straightforward, more manual and requires access to the CNE One Password account and VPN. Here is an example of how it's done for staging:
$ aws s3 cp s3://cne-db-backups/backstage/backstage_production_latest.tar.gz $HOME/dump/
$ tar xvzf $HOME/dump/backstage_production_latest.tar.gz -C $HOME/
$ mongorestore --drop --maintainInsertionOrder --stopOnError --preserveUUID \
--host=mongodb-backstage-staging1.cnedevs.com --port=27017 --username=cneops-admin \
--password=<<cneops-admin pw from One Password>> --authenticationDatabase=admin \
--db=backstage_staging --dir=$HOME/dump/backstage_production/
Running backstage apps locally
To run the frontend app locally:
npm run start:dev
To run the backstage-api server locally:
cd ../backstage-api
MONGO_DB_PORT=27017 npm run server:start
To run the app fronted by Nginx on port 8080:
docker build -t backstage-frontend .
docker run -d --name=backstage-frontend -p 8080:80 backstage-frontend
To run a staging-like build locally:
docker build --build-arg TARGET_ENV=staging -t backstage-frontend` .
docker run -d --name=bs -p 8080:80 backstage-frontend
Build & Deployment
We're using webpack as our build tool. It's pretty standard webpack stuff!
To perform a build and deploy (to ECS), you'll first want to install cne-ascension
. Installation and usage directions for the tool can be found here.. Ascension handles deployments and deployment related interactions, such as entering and exiting maintenance mode, for all environments.
To deploy using ascension these tools are available:
// to deploy from a remote branch
ascend deploy <app> <environment> REV=<branch>
...
// to deploy from your local environment
ascend deploy <app> <environment> .
...
// to enter / exit maintenance mode
ascend backstage <maint || smaint>
...
// to deploy both frontend and api at the same time
ascend backstage-all <environment> <api-location> <frontend-location>
Environment is sandbox || greybox || staging || qa || production
, and app is backstage-frontend || backstage-api
.
In the first example you can deploy code living remotely on a given branch, and with the second deploy the code (committed or not), living in your branch and directory. Either of these examples will deploy one app at a time, without entering maintenance mode. To enter maintenance mode manually, use the third command where maint
enters maintenance mode, and smaint
exits. The last command will deploy both apps together (though the api deployment will run first, followed by frontend), and will automatically enter and exit maintenance mode.
The deployment will:
- create a 1st stage docker build that runs
npm install
and builds the app withnpm run dist
- create a 2nd stage docker image that copies the built app and runs an nginx server to serve it
- push the image up to ECR
- force a new container deployment with that image in ECS
The deploy may take several minutes as ECS performs a blue/green deployment; waiting for the old services to terminate existing connections before stopping them and spinning up new containers with the updated image. You can check the deployment status in three ways:
- Via the logs and progress bar that ascension outputs to the terminal
- Via Code Deploy in the AWS Console.
- Via ECS in the AWS Console: Clusters > cne-production (or cne-nonproduction) > Service > deployments tab
Merging and Tagging
Deployment Steps & Checklist
You will notice that the default branch in this repo is #develop
, not #master
. That's by design. In order to further decouple completing features from releasing features, we never want to create branches directly off #master
. Instead, we create branches off #develop
and issue PRs from there, eventually merging into #develop
.
There are only two scenarios in which we merge into #master
--Planned Releases and Critical Hotfixes. Planned Releases should bump either the major or minor version of the project. Critical Hotfixes should only ever bump the patch version.
Given a version number [major].[minor].[patch]: | |
---|---|
MAJOR | incompatible API changes |
MINOR | add functionality (backwards-compatible) |
PATCH | bug fixes (backwards-compatible) |
Let's walk through both types of releases:
Planned Releases
- Add a commit to
#develop
that bumps the version inpackage.json
. Usually this will be a minor version.
{
"name": "backstage-client",
"version": "1.3.7",
...
- Push this commit directly into develop (no need for PR).
- Create a release branch for the release, and push it to an environment for QA
- After the release passes QA, create a tag locally for this release, using the version as your tag name:
git tag -a v1.3.7
- Add a descriptive message for the tag when prompted:
Test adding tags
* Some specific feature
* Another feature added
#
# Write a message for tag:
# v1.3.7
- Confirm your tag was added by running
git tag
:
...
v1.3.5
v1.3.6
v1.3.7
- Push your tag up to github:
git push origin v1.3.7
- Merge your release branch into
master
and push (this should trigger a staging build on Travis):
git co master
git merge <release-branch>
git push origin master
Critical Hotfixes
- In the rare cases we have a production bug so critical it can't wait for a release, create a hotfix branch directly off
#master
:git co hotfix/fix-big-bug
. - Once finished, go through the regular code review process with a PR off
#master
. - Go through the tag creation process as you would for
#develop
, but with apatch
version instead of aminor
version (e.g.1.3.7
->1.3.8
). - Merge, deploy and release
#master
exactly as you would for#develop
. -
IMPORTANT: Rebase
#develop
off#master
. This is critical to keep#develop
in sync with#master
:
git co develop
git rebase origin/master
git push origin develop -f
- Notify
#cne-backstage
on Slack that you just force pushed#develop
. Anyone with a branch off#develop
will then need to rebase off#develop
since its history has changed.
Dependency Management
NPM dependencies for this project will be updated manually on an scheduled basis. Since the project depends on a reliable package-lock.json
, we can't remove it from the repository, but we do strongly discourage updating the file outside of scheduled dependency updates.
To enforce this we've got a git commit hook in the project. To enable it:
git config core.hooksPath ./.githooks
You should do this in your backstage-api directory as well.
Tests
We're using:
- Eslint as our linter to standardize code syntax and enforce our patterns.
- Jest as our test runner.
- Enzyme for react component test helpers.
- jest-marbles for rx tests.
You can run the full suite of eslint, react, and Rx tests with:
npm test
Writing Tests
Always Be Writing Tests. For guidelines on how to write tests for this project (and other CNE React projects), see this documentation.
Generating Fixtures
Some fixtures can be generated from API responses. Seek out scripts found in
the scripts
dir for more information.
Code Style
Guidelines for this particular project are TBA. For general CNE React guidelines, refer to this documentation.
Style Guide
We use React Styleguidist as a style guide for our shared components. Run npm run docs
to start the style guide server.
Component docs are stored in /src/docs/
. You can look at existing docs for examples for adding new ones.