From c50b53d717ba9234815dccb030bebea399114b93 Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Mon, 21 Oct 2019 14:27:58 -0500 Subject: [PATCH 1/4] chore: use node-dev Docker image Signed-off-by: Eric Dobbertin --- .nvmrc | 1 + .reaction/entrypoint.sh | 26 ------------------------ .reaction/fix-volumes.sh | 34 -------------------------------- .reaction/yarnrc-docker.template | 15 -------------- Dockerfile.dev | 10 ---------- docker-compose.yml | 15 +++++++------- package.json | 3 ++- 7 files changed, 10 insertions(+), 94 deletions(-) create mode 100644 .nvmrc delete mode 100755 .reaction/entrypoint.sh delete mode 100755 .reaction/fix-volumes.sh delete mode 100644 .reaction/yarnrc-docker.template delete mode 100644 Dockerfile.dev diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..d19159826d --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +10.16.3 diff --git a/.reaction/entrypoint.sh b/.reaction/entrypoint.sh deleted file mode 100755 index ae231db285..0000000000 --- a/.reaction/entrypoint.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -# Please Use Google Shell Style: https://google.github.io/styleguide/shell.xml - -# ---- Start unofficial bash strict mode boilerplate -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -o errexit # always exit on error -set -o errtrace # trap errors in functions as well -set -o pipefail # don't ignore exit codes when piping output -set -o posix # more strict failures in subshells -# set -x # enable debugging - -IFS=$'\n\t' -# ---- End unofficial bash strict mode boilerplate - -cd "$(dirname "${BASH_SOURCE[0]}")/.." -# change the node user's uid:gid to match the repo root directory's -usermod --uid "$(stat -c "%u" .)" --non-unique node |& grep -v "no changes" || true -./.reaction/fix-volumes.sh -export NODE_ENV="${NODE_ENV:-production}" -command=(./bin/start) -if [[ $# -gt 0 ]]; then - command=($@) -fi -unset IFS -exec su-exec node ${command[*]} diff --git a/.reaction/fix-volumes.sh b/.reaction/fix-volumes.sh deleted file mode 100755 index 9d741305be..0000000000 --- a/.reaction/fix-volumes.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -# Please Use Google Shell Style: https://google.github.io/styleguide/shell.xml - -# ---- Start unofficial bash strict mode boilerplate -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -o errexit # always exit on error -set -o errtrace # trap errors in functions as well -set -o pipefail # don't ignore exit codes when piping output -set -o posix # more strict failures in subshells -# set -x # enable debugging - -IFS=$'\n\t' -# ---- End unofficial bash strict mode boilerplate - -cd "$(dirname "${BASH_SOURCE[0]}")/.." -owner=$(stat -c "%u:%g" .) -volumes=( - ./node_modules - ./build - /home/node/.cache/yarn - /home/node/.cache/yarn-offline-mirror -) -for dir in ${volumes[*]}; do - mkdir -p "${dir}" - old_owner=$(stat -c "%u:%g" "${dir}") - if [[ "$1" != "--force" && "${old_owner}" == "${owner}" ]]; then - continue - fi - printf "Fixing volume ${dir} (before=${old_owner} after=${owner})…" - chown -R "${owner}" "${dir}" - chmod -R a+r,u+rw "${dir}" - echo "✓" -done diff --git a/.reaction/yarnrc-docker.template b/.reaction/yarnrc-docker.template deleted file mode 100644 index d66e8aaa88..0000000000 --- a/.reaction/yarnrc-docker.template +++ /dev/null @@ -1,15 +0,0 @@ -# Yarn Config - configured for running inside Docker Compose - -# Configure Yarn offline mirror for improved performance. -# https://yarnpkg.com/blog/2016/11/24/offline-mirror/ -# -# If you need to ensure clean cached modules follow the guide: -# https://yarnpkg.com/blog/2016/11/24/offline-mirror/#updating-your-package -# -yarn-offline-mirror "/home/node/.cache/yarn-offline-mirror" -yarn-offline-mirror-pruning true - ---install.cache-folder /home/node/.cache/yarn ---install.ignore-scripts true ---install.modules-folder /usr/local/src/node_modules ---install.prefer-offline true diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index 87895501b6..0000000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,10 +0,0 @@ -FROM node:10-alpine -# hadolint ignore=DL3018 -RUN apk --no-cache add bash curl less shadow su-exec tini vim -SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-u", "-c"] -WORKDIR /usr/local/src/reaction-app -ENV PATH=$PATH:/usr/local/src/reaction-app/node_modules/.bin \ - BUILD_ENV=development NODE_ENV=development -# hadolint ignore=DL3002 -USER root -ENTRYPOINT ["tini", "--", "./.reaction/entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 732344360d..62abd2ca4b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,7 @@ +# This docker-compose file is used to run the Example Storefront in Docker for development. +# The local files are mounted into the created container. +# Usage: docker-compose up [-d] + version: '3.4' networks: @@ -10,9 +14,7 @@ networks: services: web: - build: - context: . - dockerfile: 'Dockerfile.dev' + image: reactioncommerce/node-dev:10.16.3-v2 env_file: - ./.env networks: @@ -23,16 +25,13 @@ services: ports: - 4000:4000 volumes: - - $HOME/.cache/yarn-offline-mirror:/home/node/.cache/yarn-offline-mirror - web-yarn:/home/node/.cache/yarn - - .:/usr/local/src/reaction-app + - .:/usr/local/src/app # Do not link in node_modules from the host # This allows IDEs to run lint etc with native add-ons for host OS # Without interfering with native add-ons in container - - empty_node_modules:/usr/local/src/reaction-app/node_modules - - node_modules:/usr/local/src/node_modules + - empty_node_modules:/usr/local/src/app/node_modules volumes: web-yarn: - node_modules: empty_node_modules: diff --git a/package.json b/package.json index 0a8b3c1e10..d7acd28103 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,12 @@ "license": "Apache-2.0", "sideEffects": false, "scripts": { - "dev": "NODE_ENV=development node ./src/server.js", + "dev": "echo 'Note: dev script has been renamed to start:dev' && yarn run start:dev", "build": "yarn run build-clean && NODE_ENV=production IS_BUILDING_NEXTJS=1 next build src", "build-clean": "rimraf build/app", "lint": "eslint .", "start": "NODE_ENV=production node ./src/server.js", + "start:dev": "NODE_ENV=development node ./src/server.js", "test": "yarn run test:unit", "test:ci": "yarn run test:unit --ci --runInBand --colors", "test:unit": "NODE_ENV=jesttest jest", From cf0727ffb1dfa72e1ac3a4f6cac948c8c657a819 Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Wed, 23 Oct 2019 11:51:42 -0500 Subject: [PATCH 2/4] chore: fix and improve prod Dockerfile Signed-off-by: Eric Dobbertin --- .env.example | 1 - Dockerfile | 40 +++++++++++++++++++++++++++++----------- README.md | 4 ++-- src/server.js | 4 ++++ 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index e5fab30b6b..11b446323d 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,6 @@ CANONICAL_URL=http://localhost:4000 ENABLE_SPA_ROUTING=true EXTERNAL_GRAPHQL_URL=http://localhost:3000/graphql-beta INTERNAL_GRAPHQL_URL=http://reaction.api.reaction.localhost:3000/graphql-beta -NODE_ENV=development OAUTH2_ADMIN_PORT=4445 OAUTH2_AUTH_URL=http://localhost:4444/oauth2/auth OAUTH2_CLIENT_ID=example-storefront diff --git a/Dockerfile b/Dockerfile index b3d831c805..a605ac2009 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,38 @@ -FROM node:10-alpine +FROM node:10.16.3-alpine + # hadolint ignore=DL3018 -RUN apk --no-cache add bash curl less tini vim +RUN apk --no-cache add bash curl less tini vim make SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-u", "-c"] -WORKDIR /usr/local/src/reaction-app -ENV PATH=$PATH:/usr/local/src/reaction-app/node_modules/.bin -# allow yarn to create ./node_modules + +WORKDIR /usr/local/src/app +ENV PATH=$PATH:/usr/local/src/app/node_modules/.bin + +# Allow yarn/npm to create ./node_modules RUN chown node:node . + +# Copy specific things so that we can keep the image as small as possible +# without relying on each repo to include a .dockerignore file. +COPY --chown=node:node package.json ./ +COPY --chown=node:node yarn.lock ./ +COPY --chown=node:node ./src ./src +COPY --chown=node:node LICENSE ./ + +# Needed only for the build command +COPY --chown=node:node .babelrc ./ + USER node -COPY --chown=node:node package.json yarn.lock ./ -# NOTE: make sure NODE_ENV is NOT "production" for this. We need devDependencies. -RUN yarn install --frozen-lockfile --ignore-scripts --non-interactive --no-cache -COPY --chown=node:node . ./ -# TODO next seems to do extra compiling/building at startup, which requires -# dev dependencies. Is there a way to get a true production build? + +# Install ALL dependencies. We need devDependencies for the build command. +RUN yarn install --production=false --frozen-lockfile --ignore-scripts --non-interactive --no-cache ENV BUILD_ENV=production NODE_ENV=production RUN IS_BUILDING_NEXTJS=1 "$(npm bin)/next" build src + +# Install only prod dependencies now that we've built, to make the image smaller +RUN rm -rf node_modules/* +RUN rm ./.babelrc +RUN yarn install --production=true --frozen-lockfile --ignore-scripts --non-interactive + +# If any Node flags are needed, they can be set in the NODE_OPTIONS env variable. CMD ["tini", "--", "node", "."] LABEL com.reactioncommerce.name="example-storefront" diff --git a/README.md b/README.md index ca58784fa0..fb11c1b888 100644 --- a/README.md +++ b/README.md @@ -185,13 +185,13 @@ Sometimes it is helpful during development to make a production build of the app Run this command to build a Docker image with the production build of the app in it: ```sh -docker build -t reaction-storefront --build-arg BUILD_ENV=production . +docker build -t reaction-storefront . ``` Then, to start the app on your machine, make sure the Reaction API container is already running and enter: ```sh -docker run -d --name storefront -p 4000:4000 --env-file .env --network api.reaction.localhost reaction-storefront +docker run -it --name storefront -p 4000:4000 --env-file .env --network api.reaction.localhost reaction-storefront ``` _**NOTE:** You can replace the number before the colon in `4000:4000` with a different localhost port you'd like the application to run at._ diff --git a/src/server.js b/src/server.js index cd83f24bb6..23335dfc10 100644 --- a/src/server.js +++ b/src/server.js @@ -10,6 +10,10 @@ const router = require("./routes"); const { configureAuthForServer } = require("./serverAuth"); const { sitemapRoutesHandler } = require("./sitemapRoutesHandler"); +if (config.isDev) { + logger.info("Running NextJS server in development mode..."); +} + // First create the NextJS app. // Note that only `config` can be used here because the NextJS `getConfig()` does not // return anything until after the NextJS app is initialized. From 16b8c7129c75e9735e2ac75389fa2d82b4445b9d Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Wed, 23 Oct 2019 11:52:16 -0500 Subject: [PATCH 3/4] chore: pull in CircleCI config improvements Same as was done in the API repo Signed-off-by: Eric Dobbertin --- .circleci/config.yml | 244 ++++++++++++++----------------------------- 1 file changed, 78 insertions(+), 166 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dff8261da8..52fc14279f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,93 +10,83 @@ version: 2 # typing. See http://yaml.org/type/merge.html for details. defaults: &defaults environment: - - DOCKER_REPOSITORY: "reactioncommerce/reaction-next-starterkit" - - DOCKER_NAMESPACE: "reactioncommerce" - - DOCKER_NAME: "reaction-next-starterkit" - - GLOBAL_CACHE_VERSION: “v3” - - KUSTOMIZE_VERSION: "3.2.1" - - HUB_VERSION: "2.12.8" - - GH_USERNAME: "rc-circleci" - - GH_EMAIL: "circleci@reactioncommerce.com" - - REACTION_GITOPS_REVIEWERS: "griggheo" - + CI_SCRIPTS: 'npx --quiet --package @reactioncommerce/ci-scripts@1.6.2' + DOCKER_REPOSITORY: "reactioncommerce/example-storefront" + DOCKER_NAMESPACE: "reactioncommerce" + DOCKER_NAME: "example-storefront" + GLOBAL_CACHE_VERSION: "v3" + KUSTOMIZE_VERSION: "3.2.1" + HUB_VERSION: "2.12.8" + GH_USERNAME: "rc-circleci" + GH_EMAIL: "circleci@reactioncommerce.com" + REACTION_GITOPS_REVIEWERS: "griggheo" docker: - - image: circleci/node:10-stretch + - image: circleci/node:12.11.1-stretch jobs: - docker-build: + install-dependencies: <<: *defaults steps: - checkout - - setup_remote_docker - - run: - name: Discover Docker Tags - command: | - (cd /tmp && npm install --no-progress @reactioncommerce/ci-scripts@1.4.0 >/dev/null) - mkdir -p docker-cache - /tmp/node_modules/.bin/docker-tags "$CIRCLE_SHA1" "$CIRCLE_BRANCH" \ - | tee docker-cache/docker-tags.txt + - restore_cache: + keys: + - reaction-v3-node-modules-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} + - reaction-v3-node-modules-{{ .Branch }} - run: - name: Docker Build - command: | - (cd /tmp && npm install --no-progress @reactioncommerce/ci-scripts@1.4.0 >/dev/null) - /tmp/node_modules/.bin/docker-labels >> Dockerfile - docker build --tag "$DOCKER_REPOSITORY:$CIRCLE_SHA1" . - mkdir -p docker-cache - docker save \ - -o docker-cache/docker-image.tar \ - "$DOCKER_REPOSITORY:$CIRCLE_SHA1" - - persist_to_workspace: - root: docker-cache + name: Install NPM dependencies + command: yarn install --production=false --frozen-lockfile --non-interactive + - save_cache: + key: reaction-v3-node-modules-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} paths: - - docker-image.tar - - docker-tags.txt - docker-push: + - node_modules + - save_cache: + key: reaction-v3-node-modules-{{ .Branch }} + paths: + - node_modules + + dockerfile-lint: <<: *defaults steps: - - setup_remote_docker - - attach_workspace: - at: docker-cache + - checkout + - setup_remote_docker: + docker_layer_caching: true - run: - name: Load and Tag Docker Image - command: | - docker load < docker-cache/docker-image.tar - cat docker-cache/docker-tags.txt \ - | xargs -t -I % \ - docker tag \ - "$DOCKER_REPOSITORY:$CIRCLE_SHA1" \ - "$DOCKER_REPOSITORY:%" + name: Lint Dockerfiles + command: ${CI_SCRIPTS} lint-dockerfiles + + eslint: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - reaction-v3-node-modules-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} + - reaction-v3-node-modules-{{ .Branch }} - run: - # Creates a new Docker repository. This is not strictly required if - # the Docker Hub defaults are set appropriately. - name: Create Private Docker Hub Repository - command: | - # Fetch a login token from environment credentials. - TOKEN=$(curl \ - -H "Content-Type: application/json" \ - -X POST \ - -d "{\"username\":\"$DOCKER_USER\",\"password\":\"$DOCKER_PASS\"}" \ - -s \ - https://hub.docker.com/v2/users/login/ \ - | jq -r .token) - # Try to create the private repo. It exits with success on fail. - curl \ - -H "Authorization: JWT $TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"namespace\":\"$DOCKER_NAMESPACE\", - \"name\":\"$DOCKER_NAME\", - \"description\":\"$DESCRIPTION\", - \"full_description\":\"\", - \"is_private\":true}" \ - https://hub.docker.com/v2/repositories/ + name: Lint JavaScript + command: yarn run lint + + test-unit: + <<: *defaults + steps: + - checkout + - restore_cache: + keys: + - reaction-v3-node-modules-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }} + - reaction-v3-node-modules-{{ .Branch }} - run: - name: Docker Push - command: | - docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" - docker push "$DOCKER_REPOSITORY:$CIRCLE_SHA1" - cat docker-cache/docker-tags.txt \ - | xargs -t -I % \ - docker push "$DOCKER_REPOSITORY:%" + name: Run Unit Tests + command: yarn run test:ci + + docker-build-push: + <<: *defaults + steps: + - checkout + - setup_remote_docker: + docker_layer_caching: true + - run: + name: Build and push production Docker image + command: ${CI_SCRIPTS} docker-build-tag-push . ${DOCKER_REPOSITORY} create-gitops-pull-request: <<: *defaults @@ -133,107 +123,29 @@ jobs: # Create PR /usr/local/bin/hub pull-request --no-edit -r ${REACTION_GITOPS_REVIEWERS} - lint-javascript: - <<: *defaults - steps: - - checkout - - run: - name: Lint JavaScript - command: | - yarn install - yarn lint - - test: - <<: *defaults - steps: - - checkout - - setup_remote_docker - - attach_workspace: - at: docker-cache - - run: - name: Load and Tag Docker Image - command: | - docker load < docker-cache/docker-image.tar - cat docker-cache/docker-tags.txt \ - | xargs -t -I % \ - docker tag \ - "$DOCKER_REPOSITORY:$CIRCLE_SHA1" \ - "$DOCKER_REPOSITORY:%" - - run: - name: Test - command: | - docker run \ - --env-file .env.example \ - --env NODE_ENV=test \ - --name reactionapp_next_starterkit \ - "$DOCKER_REPOSITORY:$CIRCLE_SHA1" \ - yarn test:ci - - run: - name: Copy test artifacts from Remote Docker - command: | - docker cp \ - reactionapp_next_starterkit:/usr/local/src/reaction-app/reports \ - reports - - store_test_results: - path: reports/junit - - store_artifacts: - path: reports - - snyk-security: - <<: *defaults - steps: - - checkout - - setup_remote_docker - - attach_workspace: - at: docker-cache - - run: - name: Load Docker Image - command: | - docker load < docker-cache/docker-image.tar - - run: - name: Snyk Security - # Snyk doesn't look up the directory tree for node_modules as - # NodeJS does so we have to take some extra measures to test in the - # Docker image. Copy package.json up a directory so that it is a - # sibling to node_modules, then run snyk test. - command: | - answer=$(./.circleci/bin/should-run-snyk.sh) - if [[ "${answer}" =~ "^YES" ]] ; then - docker run \ - --env-file .env.example \ - --env "SNYK_TOKEN" \ - --name reactionapp_next_starterkit \ - --workdir /usr/local/src \ - "$DOCKER_REPOSITORY:$CIRCLE_SHA1" \ - sh -c "cp reaction-app/package.json ./ && cp reaction-app/.snyk ./ && snyk test" - else - echo "Skipping snyk: ${answer}" - fi workflows: version: 2 build_and_test: jobs: - - lint-javascript: - context: reaction-build-read - - docker-build: - context: reaction-build-read + - install-dependencies + - dockerfile-lint: requires: - - lint-javascript - - docker-push: - context: reaction-publish-docker + - install-dependencies + - eslint: requires: - - docker-build - - test: - context: reaction-validation + - install-dependencies + - test-unit: requires: - - docker-build - - snyk-security: - context: reaction-validation + - install-dependencies + - docker-build-push: + context: reaction-publish-docker requires: - - docker-build + - dockerfile-lint + - eslint + - test-unit - create-gitops-pull-request: requires: - - docker-push + - docker-build-push filters: branches: - only: master + only: /^master$/ From f515377426bd45564e1401a615bd11486dd71da4 Mon Sep 17 00:00:00 2001 From: Erik Kieckhafer Date: Wed, 23 Oct 2019 10:55:31 -0700 Subject: [PATCH 4/4] chore: bump version for coordinated release Signed-off-by: Erik Kieckhafer --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1ff423fe..137b4419bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v2.8.0 + +Example Storefront v2.8.0 is a minor update to keep this project in sync with [Reaction v2.8.0](https://github.com/reactioncommerce/reaction) and [reaction-hydra v2.8.0](https://github.com/reactioncommerce/reaction-hydra) + # v2.7.0 Example Storefront v2.7.0 is a minor update to keep this project in sync with [Reaction v2.7.0](https://github.com/reactioncommerce/reaction) and [reaction-hydra v2.7.0](https://github.com/reactioncommerce/reaction-hydra) diff --git a/package.json b/package.json index 0a8b3c1e10..57bcc07b7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "example-storefront", - "version": "2.7.0", + "version": "2.8.0", "description": "The Example Storefront serves as a reference for implementing a web based storefront using the Reaction Commerce GraphQL API.", "main": "./src/server.js", "keywords": [],