Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add production build setup and aws CICD config files #1087

Merged
merged 4 commits into from
Apr 17, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 41 additions & 0 deletions .bin/pr-checks
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env sh

# used for script output
message () {
echo ""
echo "==========================================================================="
echo ""
echo " " "$1"
echo ""
echo "==========================================================================="
echo ""
}
STATUS=0

message "Installing dependencies with yarn..."
yarn install --frozen-lockfile

# production build - needed for some of the subsequent checks, like storybook
message "Running production build..."
cp ./docker/.env.docker.prod ./packages/venia-concept/.env
yarn run build

# jest tests - does not fail ci, failures are evaluated by danger check below
message "Running unit tests with Jest..."
yarn run test:ci

message "Running Coveralls..."
yarn run coveralls

message "Running Storybook..."
yarn workspace @magento/venia-concept run storybook:build

message "Running Bundlesize..."
yarn run bundlesize

# danger ci - eslint, prettier:validate, unit test evaluation, etc.
message "Running Danger..."
yarn run danger || STATUS=$?

echo "Exit Status: $STATUS"
exit $STATUS
32 changes: 32 additions & 0 deletions .codebuild/buildspec.deploy.demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# buildspec for deploying latest changes to main development branch
version: 0.2
env:
parameter-store:
BRAINTREE_TOKEN: "/pwa/BRAINTREE_TOKEN"
MAGENTO_BACKEND_URL: "/pwa/MAGENTO_BACKEND_URL"
phases:
pre_build:
commands:
- echo logging in to AWS ECR...
- $(aws ecr get-login --no-include-email --region us-east-1)
- echo copying env vars to env file
- sed -i "s%MAGENTO_BACKEND_URL=redacted%MAGENTO_BACKEND_URL=${MAGENTO_BACKEND_URL}%g" ./docker/.env.docker.prod
- sed -i "s/BRAINTREE_TOKEN=redacted/BRAINTREE_TOKEN=${BRAINTREE_TOKEN}/g" ./docker/.env.docker.prod
- VERSION=$CODEBUILD_RESOLVED_SOURCE_VERSION
- echo VERSION=$VERSION
build:
commands:
- echo build Docker image on `date`
- docker build -f Dockerfile.prod -t pwa-demo:latest .
- docker tag pwa-demo:latest 276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-demo:latest
- docker tag pwa-demo:latest 276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-demo:$VERSION
post_build:
commands:
- echo build Docker image complete `date`
- echo push latest Docker images to ECR...
- docker push 276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-demo:latest
- docker push 276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-demo:$VERSION
- sed -i "s/:latest/:${VERSION}/g" Dockerrun.aws.json
artifacts:
files:
- Dockerrun.aws.json
33 changes: 33 additions & 0 deletions .codebuild/buildspec.pr.build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
version: 0.2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add lifecycle policy for each ECR repo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added ✅

env:
parameter-store:
BRAINTREE_TOKEN: "/pwa/BRAINTREE_TOKEN"
MAGENTO_BACKEND_URL: "/pwa/MAGENTO_BACKEND_URL"
phases:
pre_build:
commands:
# get the PR number from version env var, originally in the format "pr/2"
- PR_ID_TAG=$(echo $CODEBUILD_SOURCE_VERSION | cut -d'/' -f 2)
- echo getting PR ID... PR_ID_TAG = $PR_ID_TAG
- echo logging in to AWS ECR...
- $(aws ecr get-login --no-include-email --region us-east-1)
- echo copying env vars to env file
- sed -i "s%MAGENTO_BACKEND_URL=redacted%MAGENTO_BACKEND_URL=${MAGENTO_BACKEND_URL}%g" ./docker/.env.docker.prod
- sed -i "s/BRAINTREE_TOKEN=redacted/BRAINTREE_TOKEN=${BRAINTREE_TOKEN}/g" ./docker/.env.docker.prod
build:
commands:
- echo build Docker image on `date` for github branch $CODEBUILD_SOURCE_VERSION
- docker build -f Dockerfile.prod -t pwa-pr-build:$PR_ID_TAG .
- docker tag pwa-pr-build:$PR_ID_TAG 276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-pr-build:$PR_ID_TAG
post_build:
commands:
- echo build Docker image complete `date` for github branch $CODEBUILD_SOURCE_VERSION
- echo push latest Docker images to ECR...
- docker push 276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-pr-build:$PR_ID_TAG
# change the Dockerrun.aws.json to use the pwa-pr-build registry address pointing at this pr image build
- sed -i "s/pwa-demo:latest/pwa-pr-build:${PR_ID_TAG}/g" Dockerrun.aws.json
artifacts:
files:
- Dockerrun.aws.json
name: pr-$(echo $CODEBUILD_SOURCE_VERSION | cut -d'/' -f 2)

42 changes: 42 additions & 0 deletions .codebuild/buildspec.pr.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
version: 0.2
env:
parameter-store:
BRAINTREE_TOKEN: "/pwa/BRAINTREE_TOKEN"
MAGENTO_BACKEND_URL: "/pwa/MAGENTO_BACKEND_URL"
DANGER_GITHUB_API_TOKEN: "/pwa/DANGER_GITHUB_API_TOKEN"
BUNDLESIZE_GITHUB_TOKEN: "/pwa/BUNDLESIZE_GITHUB_TOKEN"
COVERALLS_REPO_TOKEN: "/pwa/COVERALLS_REPO_TOKEN"
phases:
install:
commands:
- echo entering install step...
# for yarn
- curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
- echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
- apt-get update -y
- apt-get install -y yarn
pre_build:
commands:
- echo setting environment variables for CI test check services for Coveralls, BundleSize...
- COVERALLS_SERVICE_NAME=codebuild
- CI=true
- CI_PULL_REQUEST=$(echo $CODEBUILD_SOURCE_VERSION | cut -d'/' -f 2)
- CI_PULL_REQUEST_NUMBER=${CI_PULL_REQUEST}
- CI_REPO_OWNER=magento-research
- CI_REPO_NAME=pwa-studio
- CI_COMMIT_SHA=${CODEBUILD_RESOLVED_SOURCE_VERSION}
- echo copying env vars needed for build to env file...
- sed -i "s%MAGENTO_BACKEND_URL=redacted%MAGENTO_BACKEND_URL=${MAGENTO_BACKEND_URL}%g" ./docker/.env.docker.prod
- sed -i "s/BRAINTREE_TOKEN=redacted/BRAINTREE_TOKEN=${BRAINTREE_TOKEN}/g" ./docker/.env.docker.prod
build:
commands:
- echo running pr-checks script `date`
# contains all the pr check task scripts
- yarn run ci:pr-checks
post_build:
commands:
- echo pr test tasks complete `date`
artifacts:
files:
- test-results/**/*
name: $(date +%m-%d-%Y-%T)_test_results_pr-$(echo $CODEBUILD_SOURCE_VERSION | cut -d'/' -f 2)
34 changes: 13 additions & 21 deletions Dockerfile → Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ COPY packages/venia-concept/package.json ./packages/venia-concept/package.json
COPY package.json yarn.lock babel.config.js browserslist.js magento-compatibility.js ./

# install dependencies with yarn
RUN yarn install
RUN yarn install --frozen-lockfile

# copy over the rest of the package files
COPY packages ./packages
Expand All @@ -35,24 +35,16 @@ COPY ${ENVFILEPATH} ./packages/venia-concept/.env
# build the app
RUN yarn run build

#######################################################################################
# UNCOMMENT FOR PRODUCTION BUILD - not as necessary for dev env to have non-root user #
#######################################################################################
# # MULTI-STAGE BUILD
# FROM node:10.14.1-alpine
# # working directory
# WORKDIR /usr/src/app
# # copy build from previous stage
# COPY --from=build /usr/src/app .
# # create and set non-root USER
# RUN addgroup -g 1001 appuser && \
# adduser -S -u 1001 -G appuser appuser
# RUN chown -R appuser:appuser /usr/src/app && \
# chmod 755 /usr/src/app
# USER appuser
#######################################################################################

# Pass the `WEBPACK_HOST` arg from docker-compose args and set it to the HOST
ARG WEBPACK_HOST
# MULTI-STAGE BUILD
FROM node:10.14.1-alpine
# working directory
WORKDIR /usr/src/app
# node:alpine comes with a configured user and group
RUN chown -R node:node /usr/src/app
# copy build from previous stage
COPY --from=build /usr/src/app .
USER node
# Pass the `HOST` arg from docker-compose args and set it to the HOST
ARG HOST
# command to run application
CMD [ "yarn", "workspace", "@magento/venia-concept", "run", "watch", "-- --host ${WEBPACK_HOST}"]
CMD [ "yarn", "workspace", "@magento/venia-concept", "run", "watch", "-- --host ${HOST}"]
46 changes: 46 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
FROM node:10.14.1-alpine as build
# working directory
WORKDIR /usr/src/app

# global environment setup : yarn + dependencies needed to support node-gyp
RUN apk --no-cache --virtual add \
python \
make \
g++ \
yarn

# copy just the dependency files and configs needed for install
COPY packages/peregrine/package.json ./packages/peregrine/package.json
COPY packages/pwa-buildpack/package.json ./packages/pwa-buildpack/package.json
COPY packages/upward-js/package.json ./packages/upward-js/package.json
COPY packages/upward-spec/package.json ./packages/upward-spec/package.json
COPY packages/venia-concept/package.json ./packages/venia-concept/package.json
COPY package.json yarn.lock babel.config.js browserslist.js magento-compatibility.js ./

# install dependencies with yarn
RUN yarn install --frozen-lockfile

# copy over the rest of the package files
COPY packages ./packages
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you elaborate on why we can't just copy packages and run yarn install?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying over just the files needed to install takes advantage of the docker cache, which allows for faster builds when there isn't a change to an image layer, each command in the dockerfile creates a new image layer as it builds. So if no changes are made to the dependencies then those layers will build from cache on subsequent builds. after hte install we copy over the rest of the files and if there are changes to those files then it will rebuild otherwise it will build from cache. More deets on the docs


# copy configuration env file from host file system to venia-concept .env for build
COPY ./docker/.env.docker.prod ./packages/venia-concept/.env

ENV NODE_ENV=production
# build the app
RUN yarn run build


# MULTI-STAGE BUILD
FROM node:10.14.1-alpine
# working directory
WORKDIR /usr/src/app
# node:alpine comes with a configured user and group
RUN chown -R node:node /usr/src/app
# copy build from previous stage
COPY --from=build /usr/src/app .
USER node
EXPOSE 8080
ENV NODE_ENV=production
# command to run application
CMD [ "yarn", "stage:venia" ]
12 changes: 12 additions & 0 deletions Dockerrun.aws.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "276375911640.dkr.ecr.us-east-1.amazonaws.com/pwa-demo:latest",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this tag will need to update based on semantic version tagging

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is modified in each build script to be either the pr id tag or the commit SHA ✅

"Update": "true"
},
"Ports": [
{
"ContainerPort": "8080"
}
]
}
70 changes: 49 additions & 21 deletions dangerfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,33 +88,40 @@ function jUnitSuite(title) {
const time = stopwatch.stop();
fs.writeFileSync(
filename,
xml({
testsuites: [
xml(
[
{
_attr: {
tests: cases.length,
failures: failureCount,
time
}
},
{
testsuite: [
testsuites: [
{
_attr: {
name: title,
errors: errorCount,
tests: cases.length,
failures: failureCount,
skipped: 0,
timestamp: new Date().toISOString(),
time,
tests: cases.length
time
}
},
...cases
{
testsuite: [
{
_attr: {
name: title,
errors: errorCount,
failures: failureCount,
skipped: 0,
timestamp: new Date().toISOString(),
time,
tests: cases.length
}
},
...cases
]
}
]
}
]
}),
],
{
declaration: true
}
),
'utf8'
);
}
Expand All @@ -136,14 +143,15 @@ const tasks = [
stdout = result.stdout;
stderr = result.stderr;
} catch (err) {
if (typeof stdout !== 'string') {
if (err.code === 'MODULE_NOT_FOUND') {
// execa didn't require
throw err;
}
stdout = err.stdout;
stderr = err.stderr;
}
const failedFiles = stdout.split('\n').filter(s => s.trim());

// Prettier doesn't normally print the files it covered, but in debug
// mode, you can extract them with these regex (as of Prettier 1.13.5)
// This is a hack based on debug output not guaranteed to stay the same.
Expand Down Expand Up @@ -271,6 +279,7 @@ const tasks = [
'All tests must pass before this PR can be merged\n\n\n' +
failSummary
);
throw new Error(failSummary);
}

// function mergeJunitReports() {
Expand Down Expand Up @@ -306,6 +315,25 @@ const tasks = [
// }
];

const runTasks = async tasks => {
const errors = [];
for (const task of tasks) {
try {
await task();
} catch (e) {
errors.push({ task: task.name, error: e.stdout || e });
}
}
return errors;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not like performance in CI is super important, but could these tasks be run in parallel?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if Danger is going to be used more and expanded then this file should be refactored in a number of ways. I think that should be a separate endeavor outside of this pr though. Mostly what I am doing here is capturing all the errors at once and reporting all the errors, rather than only reporting the first error hit.


(async () => {
for (const task of tasks) await task();
const errors = await runTasks(tasks);
if (errors.length) {
errors.map(e => {
console.log(codeFence(`ERROR ON TASK: ${e.task}`));
console.log(e.error);
});
throw 'Danger found errors. See stack trace above.';
}
})();
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ services:
# build pwa using the Dockerfile from the PWD
build:
context: .
dockerfile: Dockerfile
dockerfile: Dockerfile.dev
args:
WEBPACK_HOST: ${PWA_STUDIO_PUBLIC_PATH}
HOST: ${PWA_STUDIO_PUBLIC_PATH}
ENVFILEPATH: ${ENVFILEPATH}
# list of directories and files on the host system to volume mount into the container
# changes made to files in the container and on the host file system are mapped to one another
Expand Down
File renamed without changes.
16 changes: 16 additions & 0 deletions docker/.env.docker.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
########## .env.docker ########################################################
#
# See packages/venia-concept/.env.dist file for full option details
#
###############################################################################

NODE_ENV=production
PORT=8080
PWA_STUDIO_PUBLIC_PATH=localhost
# magento graphql backend set to production mode
MAGENTO_BACKEND_URL=redacted
MAGENTO_BUILDPACK_PROVIDE_SECURE_HOST=0
UPWARD_JS_UPWARD_PATH=venia-upward.yml
UPWARD_JS_BIND_LOCAL=1
UPWARD_JS_LOG_URL=1
BRAINTREE_TOKEN=redacted