Build and deployment
Overview
git push
│
▼
AWS CodePipeline (one pipeline per environment: internal-client-v2-<env>)
│
├── buildspec.yml build stage
│ npm ci
│ npm run lint
│ # npm run test:ci ← currently commented out
│ ./deployment/build.sh $ENV_NAME $ENV_TYPE "$PWD/deployment"
│ ├─ npm install
│ ├─ . ./deployment/setenv.sh <env> <domain> <config-dir>
│ └─ ng build --configuration=$THIS_NODE_ENV
│ with --max_old_space_size=12288
│ artifacts: ./dist/**/*
│
└── buildspec-deploy.yml deploy stage
./deployment/deploy.sh
aws s3 sync $DIST → s3://$BUCKET_NAME/$BUCKET_PREFIX
(plus a __v<version> copy on release)
Separate specs exist for CI-only checks (buildspec-ci.yml) and Cypress
(buildspec-cypress.yml).
Angular build configurations
From angular.json. Common options: aot: true, outputHashing: 'all',
vendorChunk: false, output to dist/, src/index.html as index, plus the eight
global stylesheets, three global scripts and the TinyMCE asset copy.
| Configuration | Settings |
|---|---|
|
|
|
|
|
As staging, plus a file replacement of
|
THIS_NODE_ENV, set by setenv.sh, selects which one build.sh passes to
ng build: production for ENV_NAME=release, staging for
ENV_NAME=staging, development otherwise. See
environments.
Custom webpack
angular.json uses @angular-builders/custom-webpack:browser with
custom-webpack.config.js:
module.exports = {
plugins: [new webpack.DefinePlugin({ BUILD_TIMESTAMP: +new Date() })],
optimization: { sideEffects: false },
};
sideEffects: false disables webpack’s side-effect-based tree shaking. Given the
number of modules with import-time side effects (reducers reading localStorage,
window.$ assignment, the Segment snippet), this is load-bearing — do not enable it.
BUILD_TIMESTAMP is defined globally but not referenced by application code.
Memory
The AOT build of ~420 components exceeds Node’s default heap:
| Where | Setting |
|---|---|
|
|
|
|
A local npm run build uses the plain ng binary and can run out of memory on large
changes; use npm run build-prod or build-test instead.
allowedCommonJsDependencies suppresses CommonJS warnings for
ag-grid-enterprise, jwt-decode, angular2-moment, elasticsearch, rxjs and
payment.
deployment/build.sh
./deployment/build.sh ENV_NAME ENV_TYPE CONFIG_DIR [ENV_FILE_NAME]
ENV_TYPE chooses the domain:
if [[ "$ENV_TYPE" == "dev" ]]; then DOMAIN=dev.payability.com
else DOMAIN=payability.com; fi
It then runs npm install, sources setenv.sh (note: sourced, so the exported
variables persist), prints THIS_NODE_ENV, and builds. set -eux means the script
echoes every command and aborts on the first failure.
Buildspecs
buildspec.yml — the environment build
| Phase | Commands |
|---|---|
|
Node 12 + Python 3.8 runtimes. Fetches an SSH key pair from Secrets Manager
( |
|
|
|
|
|
So the deploy path runs lint only. Unit tests run in |
The SSH key is needed because npm ci resolves at least one dependency over SSH.
buildspec-ci.yml — checks only
install: nodejs 12; npm ci
build: npm run lint && npm run test:ci
reports:
karma-junit-report: TESTS.xml (JUNITXML)
cobertura-report: coverage/cobertura-coverage.xml
artifacts: coverage/lcov-report/**/*
No build, no deploy. This is the gate that actually runs the unit suite.
buildspec-cypress.yml — E2E
Pulls NPM_TOKEN and CYPRESS_QA_TEAM_PASSWORD from Secrets Manager
(internal-client-v2/cypress:QA_TEAM_PASSWORD), configures the GitHub npm registry,
then either runs against a locally served app or a deployed one:
if [ $CYPRESS_LOCAL = "true" ]; then
./deployment/setenv.sh $CYPRESS_ENV_NAME "dev.payability.com" "$PWD/deployment"
npm run cy:run-local-no-watch
else
npm run cy:run
fi
post_build merges the JUnit reports. Artifacts include reports, screenshots and
videos. The suite is marked not maintained — see testing.
deployment/deploy.sh
DIST_FOLDER=$CODEBUILD_SRC_DIR_BuildArtifact/dist
S3_LOCATION=s3://$BUCKET_NAME/$BUCKET_PREFIX
# deploy as the default (latest) version
aws s3 sync $DIST_FOLDER $S3_LOCATION --acl public-read --delete \
--exclude "*__v*" --region us-east-1
# OPS-131: also deploy to a versioned subfolder for release
if [[ "$ENV_NAME" == "release" ]]; then
CURRENT_VERSION=$(jq -r '.version' ./package.json)
aws s3 sync $DIST_FOLDER $S3_LOCATION/__v${CURRENT_VERSION} \
--acl public-read --delete --region us-east-1
fi
Two things to note:
-
--deleteremoves anything in the bucket prefix that is not in the artifact, but--exclude "__v"protects the versioned release folders from being swept away. -
On
release, the same assets are also published to__v<package.json version>, which is what allows switching between released versions without a rebuild (ticket OPS-131). Bumpingpackage.jsonis therefore meaningful on release.
--acl public-read: the built assets are public. Nothing secret may be in the bundle
— which is worth remembering given the hardcoded event-logger token noted in
observability.
Environments and pipelines
From the repository README:
-
All dev environments deploy from
developby default. -
Production is released by opening a pull request to
release. -
To point an environment at your branch: AWS Console → CodePipeline (dev account) → the pipeline named
internal-client-v2-<env>→ Edit → Edit stage (source) → the GitHub block → set Branch name → Done → Save. Every new HEAD on that branch then triggers a deployment; Release change forces one. -
Dev assets land in the
dev-payability-wwwbucket undercdk-<env>/admin.
deployment/reset-branches.sh force-recreates dev-1 … dev-10 from
develop and force-pushes them — the per-developer environment branches.
|
|
Docker (not the deployment path)
A Dockerfile and docker-compose.yml exist for local containerised runs, and they
are stale:
-
FROM node:8-alpine— Node 8, not the pinned 12.21.0. -
ng build --env=$environment "dist-$environment"— the pre-Angular-6 CLI flag, which the current CLI does not accept. -
Stage 2 serves
distfromnginx:1.13.3-alpinewithnginx/default.conf.
nginx/default.conf is still informative about the hosting contract: gzip on,
root /usr/share/nginx/html, and
location / { try_files $uri $uri/ /index.html =404; }
an SPA fallback to index.html. Note that hash routing (useHash: true) means deep
links do not actually depend on this rewrite — see
routing.
Release checklist
-
Merge to
develop; confirm the environment pipeline is green. -
Bump
versioninpackage.json— it becomes the__v<version>S3 folder. -
Open a pull request to
releaseusing.github/PULL_REQUEST_TEMPLATE.md. -
Confirm the
releasepipeline usedsetup_template-production.cfg(ENV_NAME=release) and therefore theproductionbuild configuration. -
Verify the deployed build: the sidebar footer shows the front-end and back-end versions.
Gotchas
| Issue | Detail |
|---|---|
Deploy build does not run tests |
|
|
The buildspec runs |
Heap size differs local vs CI |
8192 locally, 12288 in CI. |
Docker files are stale |
Node 8 and a removed CLI flag. |
|
Built assets are world-readable. |
Only |
And only if |
|
Its exports leak into the rest of |