From 1b5e9bdf197181fba6f5d7a1df69547f82953da5 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Wed, 27 Mar 2019 15:04:40 +0100 Subject: [PATCH 01/30] #43 add docker file for extension --- extension/.dockerignore | 7 +++++++ extension/Dockerfile | 12 ++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 extension/.dockerignore create mode 100644 extension/Dockerfile diff --git a/extension/.dockerignore b/extension/.dockerignore new file mode 100644 index 000000000..f77cb9dd1 --- /dev/null +++ b/extension/.dockerignore @@ -0,0 +1,7 @@ +.gitignore +.git +test +cypress +cypress. +node_modules +json \ No newline at end of file diff --git a/extension/Dockerfile b/extension/Dockerfile new file mode 100644 index 000000000..e341efb39 --- /dev/null +++ b/extension/Dockerfile @@ -0,0 +1,12 @@ +FROM mhart/alpine-node:10 +MAINTAINER Professional Services + +WORKDIR /app + +RUN apk --update add make python + +RUN apk --update add git + +COPY . /app + +RUN npm ci --only=prod \ No newline at end of file From f0dd7614ab28508214d0fed284bb134dab0d0598 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Wed, 27 Mar 2019 15:56:13 +0100 Subject: [PATCH 02/30] #43 add crypt scripts --- .gitignore | 4 +- extension/k8s/crypt/crypt.sh | 148 +++++++++++++++++++++++++++++++++ extension/k8s/crypt/decrypt.sh | 28 +++++++ extension/k8s/crypt/encrypt.sh | 27 ++++++ 4 files changed, 206 insertions(+), 1 deletion(-) create mode 100755 extension/k8s/crypt/crypt.sh create mode 100755 extension/k8s/crypt/decrypt.sh create mode 100644 extension/k8s/crypt/encrypt.sh diff --git a/.gitignore b/.gitignore index 92dc1c67d..67871fd0c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,6 @@ node_modules/ # IntelliJ .idea -*.iml \ No newline at end of file +*.iml + +secrets.yaml \ No newline at end of file diff --git a/extension/k8s/crypt/crypt.sh b/extension/k8s/crypt/crypt.sh new file mode 100755 index 000000000..0b935ca4c --- /dev/null +++ b/extension/k8s/crypt/crypt.sh @@ -0,0 +1,148 @@ +#!/bin/bash +set -e + +declare -a ACTIONS=("encrypt" "decrypt") +declare -a ENVIRONMENTS=("demo") +# Google Cloud project +PROJECT_NAME="ctp-adyen-integration-extension" +GCLOUD_PROJECT_ID="professionalserviceslabs" +SELECTED_APPLICATION="ctp-adyen-integration-extension" + +# Checks if the element exists in the array +# Usage: containsElement "${array[@]}" "blabla" +function containsElement() { + local n=$# + local value=${!n} + for ((i=1;i < $#;i++)) { + if [ "${!i}" == "${value}" ]; then + return 0 + fi + } + return 1 +} + +requireEnvironment(){ + printf "Available environments:\n" + for i in "${!ENVIRONMENTS[@]}" ; do + printf "> %s. %s\n" "$(($i+1))" "${ENVIRONMENTS[$i]}" + done + read -p "Enter the environment number: " SELECTED_ENVIRONMENT_INDEX + printf "\n" + # If the entered environment number is out of `ENVIRONMENTS` then exit + if ! [ "$SELECTED_ENVIRONMENT_INDEX" -ge 1 -a "$SELECTED_ENVIRONMENT_INDEX" -le ${#ENVIRONMENTS[@]} ]; then + printf "Wrong environment number. Exiting with 1.\n" + exit 1 + fi + # Workaround for return. Returns function parameter by reference + eval "$1='${ENVIRONMENTS[$(($SELECTED_ENVIRONMENT_INDEX-1))]}'" +} + +requireAction(){ + printf "Available actions:\n" + for i in "${!ACTIONS[@]}" ; do + printf "> %s. %s\n" "$(($i+1))" "${ACTIONS[$i]}" + done + read -p "Enter the action number: " SELECTED_ACTION_INDEX + printf "\n" + # If the entered action number is out of `ACTIONS` then exit + if ! [ "$SELECTED_ACTION_INDEX" -ge 1 -a "$SELECTED_ACTION_INDEX" -le ${#ACTIONS[@]} ]; then + printf "Wrong action number. Exiting with 1.\n" + exit 1 + fi + # Workaround for return. Returns function parameter by reference + eval "$1='${ACTIONS[$((SELECTED_ACTION_INDEX-1))]}'" +} + +includeScriptOrDie() { + COMMON_SCRIPT="$(dirname "$0")/$1" + if [ ! -r "$COMMON_SCRIPT" ] ; then + echo "Error: script [${COMMON_SCRIPT}] not found!" + exit 1 + fi + . "$COMMON_SCRIPT" +} + +# This function ensures that all necessary arguments are passed to the script. +# If no arguments passed - it asks all of them +# If only 1 argument passed - it asks for other 2 +# and so on. +# It also validates all passed arguments and returns in case of invalid one. +requireArguments() { + local ACTION_VALIDATION_ERROR_MESSAGE="Provided action is invalid." + local ENVIRONMENT_VALIDATION_ERROR_MESSAGE="Provided environment is invalid." + case "$#" in + "0") + requireAction SELECTED_ACTION + requireEnvironment SELECTED_ENVIRONMENT + requestApproval + ;; + "1") + if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@]; then + SELECTED_ACTION=$1; + else return 1 + fi + # requireApplication SELECTED_APPLICATION + requireEnvironment SELECTED_ENVIRONMENT + requestApproval + ;; + *) + if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@] && \ + # validateInput $2 "${APPLICATION_NAME_VALIDATION_ERROR_MESSAGE}" APPLICATION_NAMES[@] && \ + validateInput $2 "${ENVIRONMENT_VALIDATION_ERROR_MESSAGE}" ENVIRONMENTS[@] ; then + SELECTED_ACTION=$1 + # SELECTED_APPLICATION=$2 + SELECTED_ENVIRONMENT=$2 + else return 1 + fi + ;; + esac +} + +startEncrypt() { + includeScriptOrDie "encrypt.sh" + local ENCRYPTED_FILE='' + encrypt ENCRYPTED_FILE \ + && printf "Encrypted successfully:\n" \ + && ls -l ${ENCRYPTED_FILE} \ + && printf "Don't forget to add/commit the encrypted file\n" +} + +startDecrypt() { + local DECRYPTED_FILE='' + includeScriptOrDie "decrypt.sh" + decrypt DECRYPTED_FILE \ + && printf "\nDecrypted successfully:\n" \ + && ls -l ${DECRYPTED_FILE} +} + +requestApproval() { + while true; do + read -p "Going to execute`echo $'\n> '`${bold}${SELECTED_ACTION} ${SELECTED_APPLICATION} ${SELECTED_ENVIRONMENT} (y/n)${normal} " yn + case ${yn} in + [Yy]* ) echo "Starting to ${SELECTED_ACTION}..."; break;; + [Nn]* ) echo "Terminating process"; exit;; + * ) echo "Please answer yes or no.";; + esac + done +} + +main() { + local bold=$(tput bold) + local normal=$(tput sgr0) + requireArguments $@ || return 1 + + if [ "${SELECTED_ACTION}" = "encrypt" ] ; then + startEncrypt + else + startDecrypt + fi +} + +validateInput() { + if ! containsElement ${!3} "$1"; then + printf "$2\n" + return 1 + fi +} + +if ! main $@; then exit 1; fi \ No newline at end of file diff --git a/extension/k8s/crypt/decrypt.sh b/extension/k8s/crypt/decrypt.sh new file mode 100755 index 000000000..d9ab037c4 --- /dev/null +++ b/extension/k8s/crypt/decrypt.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" +KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" + +ENC_EXT=".enc" +SECRETS_NAME="secrets.yaml" +DIR="$( cd "$( dirname "$0" )" && pwd )" +DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" +ENCRYPTED_FILE="${DECRYPTED_FILE}${ENC_EXT}" + +decrypt() { + if [ ! -f ${ENCRYPTED_FILE} ]; then + printf "Encrypted secret file not found!\n" + return 1 + fi + + gcloud kms decrypt \ + --project="${GCLOUD_PROJECT_ID}"\ + --location="global" \ + --keyring="$KEYRING" \ + --key="$KEY" \ + --plaintext-file="${DECRYPTED_FILE}" \ + --ciphertext-file="${ENCRYPTED_FILE}" + # Workaround for return. Returns function parameter by reference + eval "$1='${DECRYPTED_FILE}'" +} \ No newline at end of file diff --git a/extension/k8s/crypt/encrypt.sh b/extension/k8s/crypt/encrypt.sh new file mode 100644 index 000000000..130b803d3 --- /dev/null +++ b/extension/k8s/crypt/encrypt.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -e + +KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" +KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" + +ENC_EXT=".enc" +SECRETS_NAME="secrets.yaml" +DIR="$( cd "$( dirname "$0" )" && pwd )" +DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" + +encrypt() { + if [ ! -f ${DECRYPTED_FILE} ]; then + printf "Secret file not found!\n" + return 1 + fi + + gcloud kms encrypt \ + --project="${GCLOUD_PROJECT_ID}"\ + --location="global" \ + --keyring="$KEYRING" \ + --key="$KEY" \ + --plaintext-file="${DECRYPTED_FILE}" \ + --ciphertext-file="${DECRYPTED_FILE}${ENC_EXT}" + # Workaround for return. Returns function parameter by reference + eval "$1='${DECRYPTED_FILE}${ENC_EXT}'" +} \ No newline at end of file From f6242810bffa2963f98628795ec918c356aaf5f0 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Wed, 27 Mar 2019 15:56:39 +0100 Subject: [PATCH 03/30] #43 add docker build file --- extension/Dockerfile | 3 ++- extension/k8s/values.yaml | 38 +++++++++++++++++++++++++++++ extension/package.json | 2 +- extension/src/{index.js => init.js} | 0 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 extension/k8s/values.yaml rename extension/src/{index.js => init.js} (100%) diff --git a/extension/Dockerfile b/extension/Dockerfile index e341efb39..a4a26baa2 100644 --- a/extension/Dockerfile +++ b/extension/Dockerfile @@ -9,4 +9,5 @@ RUN apk --update add git COPY . /app -RUN npm ci --only=prod \ No newline at end of file +RUN npm ci --only=prod +ENTRYPOINT ["npm", "run", "start"] \ No newline at end of file diff --git a/extension/k8s/values.yaml b/extension/k8s/values.yaml new file mode 100644 index 000000000..3b6264c4b --- /dev/null +++ b/extension/k8s/values.yaml @@ -0,0 +1,38 @@ +fullnameOverride: 'ctp-adyen-integration-service-extension' + +image: + repository: 'commercetoolsps/commercetools-adyen-integration-extension' + tag: 'v1.0.0' + +service: + type: 'NodePort' + +# More on resources: +# https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/resource-qos.md +# https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +# https://cloud.google.com/compute/docs/machine-types + +# When the pod is scheduled, the container is guaranteed the amount of resources requested 2GiB RAM and 300m CPU time and it is not allowed to exceed 2GB RAM and 300m of CPU time. +# This classifies the pod as "Guaranteed" +resources: + requests: + cpu: '300m' #30% of CPU time on 1 GCP Core + memory: '1Gi' #equivalent to 2GiB + limits: + cpu: '300m' #30% of CPU time on 1 GCP Core + memory: '1Gi' #equivalent to 2GB + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: 'gce' + kubernetes.io/ingress.allow-http: 'false' + +livenessProbe: + httpGet: + path: '' + + +readinessProbe: + httpGet: + path: '' diff --git a/extension/package.json b/extension/package.json index 83923bcc8..50c3573a6 100644 --- a/extension/package.json +++ b/extension/package.json @@ -5,7 +5,7 @@ "license": "MIT", "scripts": { "test": "mocha --exit --timeout 30000 --full-trace test/**/*.spec.js", - "start": "node ./src/index.js", + "start": "node ./src/init.js", "lint": "eslint .", "cypress:run": "cypress run", "cypress:open": "cypress open", diff --git a/extension/src/index.js b/extension/src/init.js similarity index 100% rename from extension/src/index.js rename to extension/src/init.js From 8ed61a90a1ba3827817fbe8f5b6f1e1d679f8581 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Wed, 27 Mar 2019 15:58:01 +0100 Subject: [PATCH 04/30] #43 add values for k8s --- extension/k8s/demo/secrets.yaml.enc | Bin 0 -> 369 bytes extension/k8s/demo/values.yaml | 12 ++++++++++++ 2 files changed, 12 insertions(+) create mode 100644 extension/k8s/demo/secrets.yaml.enc create mode 100644 extension/k8s/demo/values.yaml diff --git a/extension/k8s/demo/secrets.yaml.enc b/extension/k8s/demo/secrets.yaml.enc new file mode 100644 index 0000000000000000000000000000000000000000..c3c9328d25bc72f5a2a931a1886955a4b1a072fc GIT binary patch literal 369 zcmV-%0gnC(Bmjf}T}2Mj_bA;8vfz1_x9}XX4!Q__H&Wug*;*YF28ZDP4id-$0Il6u zYbC1ckiQq59h-P=JI?8S#GPdac2=_v_9;)hch=+w^$3-0ZY$8NRUGrN>*;@b_P}|T z?2g~y+L@8<`jR>u)V#Ln&v-B-QYv*3*$bf>BS~jk(_R#wtIM_$z;poFc zNjALWjfIUkw%z?7B`I4q&QDsY)N-~cn+jQfAjRN+2^CUwC`$q~XA~)_PQ4{U1jk-G z Date: Wed, 27 Mar 2019 17:27:43 +0100 Subject: [PATCH 05/30] #43 add default scripts from k8s charts repo --- .travis.yml | 5 ++++ travis-build/common.sh | 22 +++++++++++++++++ travis-build/gcloud-deploy.sh | 39 ++++++++++++++++++++++++++++++ travis-build/gcloud-install-sdk.sh | 30 +++++++++++++++++++++++ travis-build/gcloud-login.sh | 24 ++++++++++++++++++ travis-build/gcloud-push-image.sh | 29 ++++++++++++++++++++++ travis-build/helm-upgrade.sh | 27 +++++++++++++++++++++ travis-build/k8s-charts-clone.sh | 13 ++++++++++ 8 files changed, 189 insertions(+) create mode 100644 travis-build/common.sh create mode 100755 travis-build/gcloud-deploy.sh create mode 100755 travis-build/gcloud-install-sdk.sh create mode 100755 travis-build/gcloud-login.sh create mode 100755 travis-build/gcloud-push-image.sh create mode 100755 travis-build/helm-upgrade.sh create mode 100755 travis-build/k8s-charts-clone.sh diff --git a/.travis.yml b/.travis.yml index ad8345c7a..3bfa4b975 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,11 @@ env: - TEST_DIR=extension before_install: - npm i -g npm@^6.9.0 +before_cache: + # because travis makes cache before calling "after_success" section we must install gcloud SDK here + - $CI_SCRIPTS/gcloud-install-sdk.sh || travis_terminate 1 +services: + - docker script: - cd $TEST_DIR - npm ci diff --git a/travis-build/common.sh b/travis-build/common.sh new file mode 100644 index 000000000..7a5caec60 --- /dev/null +++ b/travis-build/common.sh @@ -0,0 +1,22 @@ +#! /bin/bash + +# common build scripts + +# verify that all the passed arguments exist as environment variable +verifyMandatoryValues() { + for envVariable in $* ; do + : "${!envVariable?Required env variable $envVariable}" + done +} + + +# This function checks if the file in the first argument $1 exists and is readable. +# If yes, then it prints the option supplied in the second argument $2 before the file path. +# +# Example: +# +# Given: $1="filename" | $2="-f" | the file with the path "filename" exists and is readable. +# Output: this function would print "-f filename" +execOptionIfFileExistsAndIsReadable() { + if [ -r "$1" ]; then printf "%s %s" "$2" "$1"; fi +} \ No newline at end of file diff --git a/travis-build/gcloud-deploy.sh b/travis-build/gcloud-deploy.sh new file mode 100755 index 000000000..f0359a379 --- /dev/null +++ b/travis-build/gcloud-deploy.sh @@ -0,0 +1,39 @@ +#! /bin/bash + +set -e + +ENVIRONMENT_NAME="$1" +SCRIPT_DIR="$(dirname "$0")" +. "${SCRIPT_DIR}/common.sh" +HELM_UPGRADE_SCRIPT="${SCRIPT_DIR}/helm-upgrade.sh" + +printf "\n- Verifying mandatory envs: [GCLOUD_ZONE GCLOUD_CLUSTER_NAME_PREFIX, PROJECT_NAME, ENVIRONMENT_NAME, HELM_CHART_TEMPLATE_NAME, HELM_VALUES_DIR, DOCKER_TAG]..\n" +verifyMandatoryValues GCLOUD_ZONE GCLOUD_CLUSTER_NAME_PREFIX PROJECT_NAME ENVIRONMENT_NAME HELM_CHART_TEMPLATE_NAME HELM_VALUES_DIR DOCKER_TAG + +# 1. Set environment variables needed for deployment scripts +printf "\n- Building environment variable [%s]..\n" "GCLOUD_CLUSTER_NAME" +case "$ENVIRONMENT_NAME" in + staging|production) + GCLOUD_CLUSTER_NAME="${GCLOUD_CLUSTER_NAME_PREFIX}-${ENVIRONMENT_NAME}" + ;; + *) + echo "Invalid 'ENVIRONMENT_NAME' value in $0. Please use either 'staging' or 'production'." + exit 1 +esac + +# 2. Connect to the gcloud cluster +printf "\n- Connecting to the gcloud cluster with name: [%s] in [%s]..\n" "$GCLOUD_CLUSTER_NAME" "$GCLOUD_ZONE" +gcloud container clusters get-credentials "$GCLOUD_CLUSTER_NAME" --zone="$GCLOUD_ZONE" + +# 3. Decrypt secrets +. "${SCRIPT_DIR}/decrypt.sh" + +# 4. Deploy all the helm charts of the repo +$HELM_UPGRADE_SCRIPT "$PROJECT_NAME" "$ENVIRONMENT_NAME" "$HELM_CHART_TEMPLATE_NAME" "$HELM_VALUES_DIR" "$DOCKER_TAG" + +# 5. Print info about current cluster state +printf "Current cluster state:\n" +printf "Helms:\n%s\n\n" "$(helm list)" +printf "Deployments:\n%s\n\n" "$(kubectl get deployments)" +printf "Cronjobs:\n%s\n\n" "$(kubectl get cronjobs)" +printf "Pods:\n%s\n\n" "$(kubectl get pods)" \ No newline at end of file diff --git a/travis-build/gcloud-install-sdk.sh b/travis-build/gcloud-install-sdk.sh new file mode 100755 index 000000000..3e7eb2ba9 --- /dev/null +++ b/travis-build/gcloud-install-sdk.sh @@ -0,0 +1,30 @@ +#! /bin/bash + +set -e + +echo "Install gcloud SDK, Helm (if not cached yet)" + +# verify mandatory values +. "$(dirname "$0")/common.sh" +verifyMandatoryValues GCLOUD_HOME GCLOUD_PATH_APPLY HELM_VERSION HELM_HOME + +if [ ! -f "$GCLOUD_PATH_APPLY" ]; then + echo Installing gcloud SDK + rm -rf "$GCLOUD_HOME" + export CLOUDSDK_CORE_DISABLE_PROMPTS=1 # SDK installation is interactive, thus prompts must be disabled + curl "https://sdk.cloud.google.com" | bash > /dev/null +fi + +if [ ! -f "$HELM_HOME/helm" ]; then + echo Installing Helm + mkdir -p "$HELM_HOME" + wget -qO- https://storage.googleapis.com/kubernetes-helm/helm-${HELM_VERSION}-linux-amd64.tar.gz | tar zxv -C "$HELM_HOME" + mv "$HELM_HOME/linux-amd64/helm" "$HELM_HOME" + rm -rf "$HELM_HOME/linux-amd64" +fi + +. "$GCLOUD_PATH_APPLY" +gcloud version + +gcloud config set disable_usage_reporting true +gcloud --quiet components update kubectl diff --git a/travis-build/gcloud-login.sh b/travis-build/gcloud-login.sh new file mode 100755 index 000000000..8077b6586 --- /dev/null +++ b/travis-build/gcloud-login.sh @@ -0,0 +1,24 @@ +#! /bin/bash + +set -e +. "$(dirname "$0")/common.sh" + +echo "Login to gcloud and select project" + +# GCLOUD_KEY expected to be exported as JSON string in Travis settings +# don't forget single quotes around the value (like: +# '{"key":"val"}' +# ) + +# verify mandatory values +verifyMandatoryValues GCLOUD_KEY GCLOUD_PROJECT_ID GCLOUD_ZONE + +# temporary file to store credentials from env variable value, +# because gcloud supports service account logging-in only from file +GCLOUD_CREDENTIALS="$PWD/client-secret.json" +echo "$GCLOUD_KEY" > "${GCLOUD_CREDENTIALS}" + +# Auth, $GCLOUD_KEY must be set in Travis settings +gcloud auth activate-service-account --key-file "${GCLOUD_CREDENTIALS}" +gcloud config set project "$GCLOUD_PROJECT_ID" +gcloud config set compute/zone "$GCLOUD_ZONE" diff --git a/travis-build/gcloud-push-image.sh b/travis-build/gcloud-push-image.sh new file mode 100755 index 000000000..a5901b790 --- /dev/null +++ b/travis-build/gcloud-push-image.sh @@ -0,0 +1,29 @@ +#! /bin/bash + +# re-tag "${PROJECT_NAME}:latest" docker image with new registry and commit hash values, +# and push gcloud docker registry. +# this script expects the gcloud SDK is installed and user is logged in. +# See gcloud-login.sh + +set -e +. "$(dirname "$0")/common.sh" + +echo "Gcloud Push Image Script" + +# verify mandatory values +verifyMandatoryValues GCLOUD_PROJECT_ID PROJECT_NAME DOCKER_TAG REGISTRY_NAME + +IMAGE_NAME_LATEST="${PROJECT_NAME}:latest" # local built image name, must already exist +IMAGE_NAME_COMMIT="${PROJECT_NAME}:${DOCKER_TAG}" # image with git tag to push to the registry +FULL_IMAGE_NAME="${REGISTRY_NAME}/${GCLOUD_PROJECT_ID}/${IMAGE_NAME_COMMIT}" + +printf "current gcloud account: [%s]" "$(gcloud config get-value account)" + +# allow docker client push images to gcloud, \ +# "yes" is to allow update local Docker configuration file ~/.docker/config.json +yes | gcloud auth configure-docker + +echo "Pushing new docker image [${FULL_IMAGE_NAME}]" +# Push to Google container registry +docker tag "${IMAGE_NAME_LATEST}" "${FULL_IMAGE_NAME}" +docker push -- "${FULL_IMAGE_NAME}" \ No newline at end of file diff --git a/travis-build/helm-upgrade.sh b/travis-build/helm-upgrade.sh new file mode 100755 index 000000000..efb7a5a8b --- /dev/null +++ b/travis-build/helm-upgrade.sh @@ -0,0 +1,27 @@ +#! /bin/bash + +set -e + +APPLICATION_NAME="$1" +ENVIRONMENT_NAME="$2" +HELM_CHART_TEMPLATE_NAME="$3" +HELM_VALUES_DIR="$4" +IMAGE_TAG="$5" +SCRIPT_DIR="$(dirname "$0")" +CHARTS_DIR="${SCRIPT_DIR}/../../../charts" + +printf "\n- Verifying mandatory envs: [APPLICATION_NAME, ENVIRONMENT_NAME, HELM_CHART_TEMPLATE_NAME, HELM_VALUES_DIR, IMAGE_TAG]..\n" +. "${SCRIPT_DIR}/common.sh" +verifyMandatoryValues APPLICATION_NAME ENVIRONMENT_NAME HELM_CHART_TEMPLATE_NAME HELM_VALUES_DIR IMAGE_TAG + +COMMON_INSENSITIVE_ENVS_FILE="$HELM_VALUES_DIR/values.yaml" +ENVIRONMENT_SPECIFIC_INSENSITIVE_ENVS_FILE="$HELM_VALUES_DIR/$ENVIRONMENT_NAME/values.yaml" +SENSITIVE_ENVS_FILE="$HELM_VALUES_DIR/$ENVIRONMENT_NAME/secrets.yaml" + +printf "\n- Upgrading [%s] helm chart template with release name: [%s] on [%s] environment.\n" "$HELM_CHART_TEMPLATE_NAME" "$APPLICATION_NAME" "$ENVIRONMENT_NAME" +helm upgrade --install "$APPLICATION_NAME" --namespace "$ENVIRONMENT_NAME" \ + $(execOptionIfFileExistsAndIsReadable "$COMMON_INSENSITIVE_ENVS_FILE" "-f") \ + $(execOptionIfFileExistsAndIsReadable "$ENVIRONMENT_SPECIFIC_INSENSITIVE_ENVS_FILE" "-f") \ + $(execOptionIfFileExistsAndIsReadable "$SENSITIVE_ENVS_FILE" "-f") \ + $( if [[ -n $IMAGE_TAG ]]; then printf "%s" "--set-string image.tag=${IMAGE_TAG}"; fi ) \ + "$CHARTS_DIR/$HELM_CHART_TEMPLATE_NAME/" diff --git a/travis-build/k8s-charts-clone.sh b/travis-build/k8s-charts-clone.sh new file mode 100755 index 000000000..0f4614507 --- /dev/null +++ b/travis-build/k8s-charts-clone.sh @@ -0,0 +1,13 @@ +#! /bin/bash + +set -e + +CHARTS_DIR="$1" +SCRIPT_DIR="$(dirname "$0")" + +printf "\n- Verifying mandatory envs: [HELM_CHARTS_REPO, HELM_CHARTS_VERSION, CHARTS_DIR]..\n" +. "${SCRIPT_DIR}/common.sh" +verifyMandatoryValues HELM_CHARTS_REPO HELM_CHARTS_VERSION CHARTS_DIR + +printf "\n- Cloning commercetools/k8s-charts repo..\n" +git clone --branch="$HELM_CHARTS_VERSION" --depth=1 "$HELM_CHARTS_REPO" "$CHARTS_DIR"/ \ No newline at end of file From 96dfde0c92edaf602f926378db1a012e38a9e30c Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Thu, 28 Mar 2019 14:26:20 +0100 Subject: [PATCH 06/30] #43 update travis scripts --- travis-build/gcloud-deploy.sh | 6 +++--- travis-build/gcloud-push-image.sh | 2 +- travis-build/helm-upgrade.sh | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/travis-build/gcloud-deploy.sh b/travis-build/gcloud-deploy.sh index f0359a379..1c8fe28e0 100755 --- a/travis-build/gcloud-deploy.sh +++ b/travis-build/gcloud-deploy.sh @@ -1,6 +1,6 @@ #! /bin/bash -set -e +set -x ENVIRONMENT_NAME="$1" SCRIPT_DIR="$(dirname "$0")" @@ -13,7 +13,7 @@ verifyMandatoryValues GCLOUD_ZONE GCLOUD_CLUSTER_NAME_PREFIX PROJECT_NAME ENVIRO # 1. Set environment variables needed for deployment scripts printf "\n- Building environment variable [%s]..\n" "GCLOUD_CLUSTER_NAME" case "$ENVIRONMENT_NAME" in - staging|production) + staging|production|demo) GCLOUD_CLUSTER_NAME="${GCLOUD_CLUSTER_NAME_PREFIX}-${ENVIRONMENT_NAME}" ;; *) @@ -26,7 +26,7 @@ printf "\n- Connecting to the gcloud cluster with name: [%s] in [%s]..\n" "$GCLO gcloud container clusters get-credentials "$GCLOUD_CLUSTER_NAME" --zone="$GCLOUD_ZONE" # 3. Decrypt secrets -. "${SCRIPT_DIR}/decrypt.sh" +. "./extension/k8s/crypt/decrypt.sh" # 4. Deploy all the helm charts of the repo $HELM_UPGRADE_SCRIPT "$PROJECT_NAME" "$ENVIRONMENT_NAME" "$HELM_CHART_TEMPLATE_NAME" "$HELM_VALUES_DIR" "$DOCKER_TAG" diff --git a/travis-build/gcloud-push-image.sh b/travis-build/gcloud-push-image.sh index a5901b790..e76464b8a 100755 --- a/travis-build/gcloud-push-image.sh +++ b/travis-build/gcloud-push-image.sh @@ -11,7 +11,7 @@ set -e echo "Gcloud Push Image Script" # verify mandatory values -verifyMandatoryValues GCLOUD_PROJECT_ID PROJECT_NAME DOCKER_TAG REGISTRY_NAME +verifyMandatoryValues PROJECT_NAME DOCKER_TAG GCLOUD_PROJECT_ID REGISTRY_NAME IMAGE_NAME_LATEST="${PROJECT_NAME}:latest" # local built image name, must already exist IMAGE_NAME_COMMIT="${PROJECT_NAME}:${DOCKER_TAG}" # image with git tag to push to the registry diff --git a/travis-build/helm-upgrade.sh b/travis-build/helm-upgrade.sh index efb7a5a8b..6d709e752 100755 --- a/travis-build/helm-upgrade.sh +++ b/travis-build/helm-upgrade.sh @@ -8,7 +8,7 @@ HELM_CHART_TEMPLATE_NAME="$3" HELM_VALUES_DIR="$4" IMAGE_TAG="$5" SCRIPT_DIR="$(dirname "$0")" -CHARTS_DIR="${SCRIPT_DIR}/../../../charts" +CHARTS_DIR="${SCRIPT_DIR}/../../chart-templates/charts" printf "\n- Verifying mandatory envs: [APPLICATION_NAME, ENVIRONMENT_NAME, HELM_CHART_TEMPLATE_NAME, HELM_VALUES_DIR, IMAGE_TAG]..\n" . "${SCRIPT_DIR}/common.sh" From e932598915aa693c6d094ff29bbee46133fd871a Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Thu, 28 Mar 2019 14:33:54 +0100 Subject: [PATCH 07/30] #43 update k8s values --- extension/k8s/demo/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/k8s/demo/values.yaml b/extension/k8s/demo/values.yaml index 6141313b8..2daad6c51 100644 --- a/extension/k8s/demo/values.yaml +++ b/extension/k8s/demo/values.yaml @@ -6,7 +6,7 @@ nonSensitiveEnvs: ingress: annotations: - kubernetes.io/ingress.global-static-ip-name: 'paypal-plus-prod-global-ip' + kubernetes.io/ingress.global-static-ip-name: 'ctp-adyen-integration-demo-extension-global-ip' ingress.gcp.kubernetes.io/pre-shared-cert: 'ct-app' hosts: - 'adyen-payment-demo.ct-app.com' \ No newline at end of file From c3cffc99a26bea4fe5406ea9935918bf24a0eb43 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Thu, 28 Mar 2019 14:33:54 +0100 Subject: [PATCH 08/30] #43 update k8s values --- extension/k8s/demo/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/k8s/demo/values.yaml b/extension/k8s/demo/values.yaml index 6141313b8..316e4880e 100644 --- a/extension/k8s/demo/values.yaml +++ b/extension/k8s/demo/values.yaml @@ -6,7 +6,7 @@ nonSensitiveEnvs: ingress: annotations: - kubernetes.io/ingress.global-static-ip-name: 'paypal-plus-prod-global-ip' + kubernetes.io/ingress.global-static-ip-name: 'ctp-adyen-integration-demo-extension-global-ip' ingress.gcp.kubernetes.io/pre-shared-cert: 'ct-app' hosts: - - 'adyen-payment-demo.ct-app.com' \ No newline at end of file + - 'adyen-payment-demo-extension.ct-app.com' \ No newline at end of file From c1d3ced054b2224f89940c9b1f60b31c78fcec07 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Thu, 28 Mar 2019 16:19:54 +0100 Subject: [PATCH 09/30] #43 update k8s values --- extension/k8s/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/k8s/values.yaml b/extension/k8s/values.yaml index 3b6264c4b..cd4576289 100644 --- a/extension/k8s/values.yaml +++ b/extension/k8s/values.yaml @@ -1,7 +1,7 @@ fullnameOverride: 'ctp-adyen-integration-service-extension' image: - repository: 'commercetoolsps/commercetools-adyen-integration-extension' + repository: 'eu.gcr.io/professionalserviceslabs/ctp-adyen-integration-notification' tag: 'v1.0.0' service: From 8bb569f288e2a58ce2e967219fa4056fbc1f308a Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Thu, 28 Mar 2019 16:48:47 +0100 Subject: [PATCH 10/30] add deployment to k8s --- notification/.dockerignore | 7 ++ notification/Dockerfile | 13 +++ notification/k8s/crypt/crypt.sh | 148 +++++++++++++++++++++++++ notification/k8s/crypt/decrypt.sh | 28 +++++ notification/k8s/crypt/encrypt.sh | 27 +++++ notification/k8s/demo/secrets.yaml.enc | Bin 0 -> 193 bytes notification/k8s/demo/values.yaml | 9 ++ notification/k8s/values.yaml | 40 +++++++ 8 files changed, 272 insertions(+) create mode 100644 notification/.dockerignore create mode 100644 notification/Dockerfile create mode 100755 notification/k8s/crypt/crypt.sh create mode 100755 notification/k8s/crypt/decrypt.sh create mode 100644 notification/k8s/crypt/encrypt.sh create mode 100644 notification/k8s/demo/secrets.yaml.enc create mode 100644 notification/k8s/demo/values.yaml create mode 100644 notification/k8s/values.yaml diff --git a/notification/.dockerignore b/notification/.dockerignore new file mode 100644 index 000000000..f77cb9dd1 --- /dev/null +++ b/notification/.dockerignore @@ -0,0 +1,7 @@ +.gitignore +.git +test +cypress +cypress. +node_modules +json \ No newline at end of file diff --git a/notification/Dockerfile b/notification/Dockerfile new file mode 100644 index 000000000..a4a26baa2 --- /dev/null +++ b/notification/Dockerfile @@ -0,0 +1,13 @@ +FROM mhart/alpine-node:10 +MAINTAINER Professional Services + +WORKDIR /app + +RUN apk --update add make python + +RUN apk --update add git + +COPY . /app + +RUN npm ci --only=prod +ENTRYPOINT ["npm", "run", "start"] \ No newline at end of file diff --git a/notification/k8s/crypt/crypt.sh b/notification/k8s/crypt/crypt.sh new file mode 100755 index 000000000..8f6943143 --- /dev/null +++ b/notification/k8s/crypt/crypt.sh @@ -0,0 +1,148 @@ +#!/bin/bash +set -e + +declare -a ACTIONS=("encrypt" "decrypt") +declare -a ENVIRONMENTS=("demo") +# Google Cloud project +PROJECT_NAME="ctp-adyen-integration-notification" +GCLOUD_PROJECT_ID="professionalserviceslabs" +SELECTED_APPLICATION="ctp-adyen-integration-notification" + +# Checks if the element exists in the array +# Usage: containsElement "${array[@]}" "blabla" +function containsElement() { + local n=$# + local value=${!n} + for ((i=1;i < $#;i++)) { + if [ "${!i}" == "${value}" ]; then + return 0 + fi + } + return 1 +} + +requireEnvironment(){ + printf "Available environments:\n" + for i in "${!ENVIRONMENTS[@]}" ; do + printf "> %s. %s\n" "$(($i+1))" "${ENVIRONMENTS[$i]}" + done + read -p "Enter the environment number: " SELECTED_ENVIRONMENT_INDEX + printf "\n" + # If the entered environment number is out of `ENVIRONMENTS` then exit + if ! [ "$SELECTED_ENVIRONMENT_INDEX" -ge 1 -a "$SELECTED_ENVIRONMENT_INDEX" -le ${#ENVIRONMENTS[@]} ]; then + printf "Wrong environment number. Exiting with 1.\n" + exit 1 + fi + # Workaround for return. Returns function parameter by reference + eval "$1='${ENVIRONMENTS[$(($SELECTED_ENVIRONMENT_INDEX-1))]}'" +} + +requireAction(){ + printf "Available actions:\n" + for i in "${!ACTIONS[@]}" ; do + printf "> %s. %s\n" "$(($i+1))" "${ACTIONS[$i]}" + done + read -p "Enter the action number: " SELECTED_ACTION_INDEX + printf "\n" + # If the entered action number is out of `ACTIONS` then exit + if ! [ "$SELECTED_ACTION_INDEX" -ge 1 -a "$SELECTED_ACTION_INDEX" -le ${#ACTIONS[@]} ]; then + printf "Wrong action number. Exiting with 1.\n" + exit 1 + fi + # Workaround for return. Returns function parameter by reference + eval "$1='${ACTIONS[$((SELECTED_ACTION_INDEX-1))]}'" +} + +includeScriptOrDie() { + COMMON_SCRIPT="$(dirname "$0")/$1" + if [ ! -r "$COMMON_SCRIPT" ] ; then + echo "Error: script [${COMMON_SCRIPT}] not found!" + exit 1 + fi + . "$COMMON_SCRIPT" +} + +# This function ensures that all necessary arguments are passed to the script. +# If no arguments passed - it asks all of them +# If only 1 argument passed - it asks for other 2 +# and so on. +# It also validates all passed arguments and returns in case of invalid one. +requireArguments() { + local ACTION_VALIDATION_ERROR_MESSAGE="Provided action is invalid." + local ENVIRONMENT_VALIDATION_ERROR_MESSAGE="Provided environment is invalid." + case "$#" in + "0") + requireAction SELECTED_ACTION + requireEnvironment SELECTED_ENVIRONMENT + requestApproval + ;; + "1") + if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@]; then + SELECTED_ACTION=$1; + else return 1 + fi + # requireApplication SELECTED_APPLICATION + requireEnvironment SELECTED_ENVIRONMENT + requestApproval + ;; + *) + if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@] && \ + # validateInput $2 "${APPLICATION_NAME_VALIDATION_ERROR_MESSAGE}" APPLICATION_NAMES[@] && \ + validateInput $2 "${ENVIRONMENT_VALIDATION_ERROR_MESSAGE}" ENVIRONMENTS[@] ; then + SELECTED_ACTION=$1 + # SELECTED_APPLICATION=$2 + SELECTED_ENVIRONMENT=$2 + else return 1 + fi + ;; + esac +} + +startEncrypt() { + includeScriptOrDie "encrypt.sh" + local ENCRYPTED_FILE='' + encrypt ENCRYPTED_FILE \ + && printf "Encrypted successfully:\n" \ + && ls -l ${ENCRYPTED_FILE} \ + && printf "Don't forget to add/commit the encrypted file\n" +} + +startDecrypt() { + local DECRYPTED_FILE='' + includeScriptOrDie "decrypt.sh" + decrypt DECRYPTED_FILE \ + && printf "\nDecrypted successfully:\n" \ + && ls -l ${DECRYPTED_FILE} +} + +requestApproval() { + while true; do + read -p "Going to execute`echo $'\n> '`${bold}${SELECTED_ACTION} ${SELECTED_APPLICATION} ${SELECTED_ENVIRONMENT} (y/n)${normal} " yn + case ${yn} in + [Yy]* ) echo "Starting to ${SELECTED_ACTION}..."; break;; + [Nn]* ) echo "Terminating process"; exit;; + * ) echo "Please answer yes or no.";; + esac + done +} + +main() { + local bold=$(tput bold) + local normal=$(tput sgr0) + requireArguments $@ || return 1 + + if [ "${SELECTED_ACTION}" = "encrypt" ] ; then + startEncrypt + else + startDecrypt + fi +} + +validateInput() { + if ! containsElement ${!3} "$1"; then + printf "$2\n" + return 1 + fi +} + +if ! main $@; then exit 1; fi diff --git a/notification/k8s/crypt/decrypt.sh b/notification/k8s/crypt/decrypt.sh new file mode 100755 index 000000000..d9ab037c4 --- /dev/null +++ b/notification/k8s/crypt/decrypt.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" +KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" + +ENC_EXT=".enc" +SECRETS_NAME="secrets.yaml" +DIR="$( cd "$( dirname "$0" )" && pwd )" +DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" +ENCRYPTED_FILE="${DECRYPTED_FILE}${ENC_EXT}" + +decrypt() { + if [ ! -f ${ENCRYPTED_FILE} ]; then + printf "Encrypted secret file not found!\n" + return 1 + fi + + gcloud kms decrypt \ + --project="${GCLOUD_PROJECT_ID}"\ + --location="global" \ + --keyring="$KEYRING" \ + --key="$KEY" \ + --plaintext-file="${DECRYPTED_FILE}" \ + --ciphertext-file="${ENCRYPTED_FILE}" + # Workaround for return. Returns function parameter by reference + eval "$1='${DECRYPTED_FILE}'" +} \ No newline at end of file diff --git a/notification/k8s/crypt/encrypt.sh b/notification/k8s/crypt/encrypt.sh new file mode 100644 index 000000000..130b803d3 --- /dev/null +++ b/notification/k8s/crypt/encrypt.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -e + +KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" +KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" + +ENC_EXT=".enc" +SECRETS_NAME="secrets.yaml" +DIR="$( cd "$( dirname "$0" )" && pwd )" +DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" + +encrypt() { + if [ ! -f ${DECRYPTED_FILE} ]; then + printf "Secret file not found!\n" + return 1 + fi + + gcloud kms encrypt \ + --project="${GCLOUD_PROJECT_ID}"\ + --location="global" \ + --keyring="$KEYRING" \ + --key="$KEY" \ + --plaintext-file="${DECRYPTED_FILE}" \ + --ciphertext-file="${DECRYPTED_FILE}${ENC_EXT}" + # Workaround for return. Returns function parameter by reference + eval "$1='${DECRYPTED_FILE}${ENC_EXT}'" +} \ No newline at end of file diff --git a/notification/k8s/demo/secrets.yaml.enc b/notification/k8s/demo/secrets.yaml.enc new file mode 100644 index 0000000000000000000000000000000000000000..9cee0a3821d313ce1719871e79f3e3d95fa317b3 GIT binary patch literal 193 zcmV;y06zZ;Bmjf}T}3N^ylE*FqRa8iZ)52IihUmkGPXQFaQGpT3RgiSg8Ze` vREpD4Q-|}pbX;=JC3#iFhtp!wwS!n>=Yp!ACY|v{9}}rZKc<(ioxazPDH&gb literal 0 HcmV?d00001 diff --git a/notification/k8s/demo/values.yaml b/notification/k8s/demo/values.yaml new file mode 100644 index 000000000..0e189f9be --- /dev/null +++ b/notification/k8s/demo/values.yaml @@ -0,0 +1,9 @@ +nonSensitiveEnvs: + CTP_PROJECT_KEY: adyen-integration-test + +ingress: + annotations: + kubernetes.io/ingress.global-static-ip-name: 'ctp-adyen-integration-demo-notification-global-ip' + ingress.gcp.kubernetes.io/pre-shared-cert: 'ct-app' + hosts: + - 'adyen-payment-demo-notification.ct-app.com' diff --git a/notification/k8s/values.yaml b/notification/k8s/values.yaml new file mode 100644 index 000000000..dbe19ca26 --- /dev/null +++ b/notification/k8s/values.yaml @@ -0,0 +1,40 @@ +fullnameOverride: 'ctp-adyen-integration-service-notification' + +image: + repository: 'eu.gcr.io/professionalserviceslabs/ctp-adyen-integration-notification' + tag: '1.1' + +service: + type: 'NodePort' + +# More on resources: +# https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/resource-qos.md +# https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ +# https://cloud.google.com/compute/docs/machine-types + +# When the pod is scheduled, the container is guaranteed the amount of resources requested 2GiB RAM and 300m CPU time and it is not allowed to exceed 2GB RAM and 300m of CPU time. +# This classifies the pod as "Guaranteed" +#resources: +# requests: +# cpu: '300m' #30% of CPU time on 1 GCP Core +# memory: '1Gi' #equivalent to 2GiB +# limits: +# cpu: '300m' #30% of CPU time on 1 GCP Core +# memory: '1Gi' #equivalent to 2GB + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: 'gce' + kubernetes.io/ingress.allow-http: 'false' + +containerPort: 443 + +livenessProbe: + httpGet: + path: '' + + +readinessProbe: + httpGet: + path: '' From caf1393a8e2c9ab85a00987cdb50f949fbc60706 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Thu, 28 Mar 2019 16:50:01 +0100 Subject: [PATCH 11/30] fix destructuring --- .../resources/payment-interface-interaction-types.json | 0 notification/src/api/notification/notification.controller.js | 2 ++ .../config/init/ensure-interface-interaction-custom-type.js | 2 +- notification/src/server.js | 4 ++-- travis-build/gcloud-deploy.sh | 4 ++-- 5 files changed, 7 insertions(+), 5 deletions(-) rename notification/{test => }/resources/payment-interface-interaction-types.json (100%) diff --git a/notification/test/resources/payment-interface-interaction-types.json b/notification/resources/payment-interface-interaction-types.json similarity index 100% rename from notification/test/resources/payment-interface-interaction-types.json rename to notification/resources/payment-interface-interaction-types.json diff --git a/notification/src/api/notification/notification.controller.js b/notification/src/api/notification/notification.controller.js index 00888564b..200ee5fd2 100644 --- a/notification/src/api/notification/notification.controller.js +++ b/notification/src/api/notification/notification.controller.js @@ -9,6 +9,8 @@ const ctpClient = ctp.get(config) // TODO: add JSON schema validation: // https://github.com/commercetools/commercetools-adyen-integration/issues/9 async function handleNotification (request, response) { + if (request.method !== 'POST') + return httpUtils.sendResponse(response) const body = await httpUtils.collectRequestData(request) try { const notifications = _.get(JSON.parse(body), 'notificationItems', []) diff --git a/notification/src/config/init/ensure-interface-interaction-custom-type.js b/notification/src/config/init/ensure-interface-interaction-custom-type.js index 719417cff..a9e54f59b 100644 --- a/notification/src/config/init/ensure-interface-interaction-custom-type.js +++ b/notification/src/config/init/ensure-interface-interaction-custom-type.js @@ -1,6 +1,6 @@ const Promise = require('bluebird') -const interfaceInteractionTypes = require('../../../test/resources/payment-interface-interaction-types.json') +const interfaceInteractionTypes = require('../../../resources/payment-interface-interaction-types.json') async function ensureInterfaceInteractionCustomType (ctpClient) { await Promise.map(interfaceInteractionTypes, async (type) => { diff --git a/notification/src/server.js b/notification/src/server.js index f4247bae7..f5af134a1 100644 --- a/notification/src/server.js +++ b/notification/src/server.js @@ -16,10 +16,10 @@ function setupServer (routes = defaultRoutes) { await route(request, response) } catch (e) { logger.error(e, `Unexpected error when processing URL ${JSON.stringify(parts)}`) - utils.sendResponse({ response, statusCode: 500 }) + utils.sendResponse(response, 500) } else - utils.sendResponse({ response, statusCode: 404 }) + utils.sendResponse(response, 404) }) } diff --git a/travis-build/gcloud-deploy.sh b/travis-build/gcloud-deploy.sh index 1c8fe28e0..6defbdf38 100755 --- a/travis-build/gcloud-deploy.sh +++ b/travis-build/gcloud-deploy.sh @@ -1,6 +1,6 @@ #! /bin/bash -set -x +set -e ENVIRONMENT_NAME="$1" SCRIPT_DIR="$(dirname "$0")" @@ -36,4 +36,4 @@ printf "Current cluster state:\n" printf "Helms:\n%s\n\n" "$(helm list)" printf "Deployments:\n%s\n\n" "$(kubectl get deployments)" printf "Cronjobs:\n%s\n\n" "$(kubectl get cronjobs)" -printf "Pods:\n%s\n\n" "$(kubectl get pods)" \ No newline at end of file +printf "Pods:\n%s\n\n" "$(kubectl get pods)" From 5c411f3bfb3d36735ced8df8cbd1edfffc3a22b2 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Fri, 29 Mar 2019 11:33:01 +0100 Subject: [PATCH 12/30] #43 update k8s values --- extension/k8s/crypt/crypt.sh | 2 +- extension/k8s/demo/secrets.yaml.enc | Bin 369 -> 369 bytes extension/k8s/demo/values.yaml | 4 ++-- extension/k8s/values.yaml | 4 ++-- notification/k8s/crypt/crypt.sh | 2 +- notification/k8s/demo/secrets.yaml.enc | Bin 193 -> 193 bytes notification/k8s/demo/values.yaml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/extension/k8s/crypt/crypt.sh b/extension/k8s/crypt/crypt.sh index 0b935ca4c..e684b3c01 100755 --- a/extension/k8s/crypt/crypt.sh +++ b/extension/k8s/crypt/crypt.sh @@ -4,7 +4,7 @@ set -e declare -a ACTIONS=("encrypt" "decrypt") declare -a ENVIRONMENTS=("demo") # Google Cloud project -PROJECT_NAME="ctp-adyen-integration-extension" +PROJECT_NAME="ctp-adyen-integration" GCLOUD_PROJECT_ID="professionalserviceslabs" SELECTED_APPLICATION="ctp-adyen-integration-extension" diff --git a/extension/k8s/demo/secrets.yaml.enc b/extension/k8s/demo/secrets.yaml.enc index c3c9328d25bc72f5a2a931a1886955a4b1a072fc..00093b3c6cb1f9c95d46eb34206d79a63bf9509d 100644 GIT binary patch literal 369 zcmV-%0gnC(Bmix$qywt;g)S4XR5HI%FpV#iRVYTSyv`taCL3fBJ+`Ho;}XaM0BD@d z_+Ooy-3^O6LPT3X){KZ>$LkNeB|6W z4ERAS3Rr9 zm9_>9vRbnwE|P;q%dY;>7-KrbhppM3LuZ+8ROB4QBu-&_^$pB_?0Ce$ne^)yFekOB zn-G5Wa^Fa=*a#almou6+o;XSFXR!3V1aLYElXCdoR4RuJvXxZ%hr-lQ1gI_ za}n`+T-v**LN-iotVd6%tQ~Y@;mZBw>UtroV|7`uI25Ffl!8)P2ndLr(SJMdBRrzl zkK!!wo05~5zwENM?OI<-b9db+AlV~bpoekj PPAvRSSLpES>Mcvgsf@O6 literal 369 zcmV-%0gnC(Bmjf}T}2Mj_bA;8vfz1_x9}XX4!Q__H&Wug*;*YF28ZDP4id-$0Il6u zYbC1ckiQq59h-P=JI?8S#GPdac2=_v_9;)hch=+w^$3-0ZY$8NRUGrN>*;@b_P}|T z?2g~y+L@8<`jR>u)V#Ln&v-B-QYv*3*$bf>BS~jk(_R#wtIM_$z;poFc zNjALWjfIUkw%z?7B`I4q&QDsY)N-~cn+jQfAjRN+2^CUwC`$q~XA~)_PQ4{U1jk-G z)52IihUmkGPXQFaQGpT3RgiSg8Ze` vREpD4Q-|}pbX;=JC3#iFhtp!wwS!n>=Yp!ACY|v{9}}rZKc<(ioxazPDH&gb diff --git a/notification/k8s/demo/values.yaml b/notification/k8s/demo/values.yaml index 0e189f9be..381c2c2a2 100644 --- a/notification/k8s/demo/values.yaml +++ b/notification/k8s/demo/values.yaml @@ -1,5 +1,5 @@ nonSensitiveEnvs: - CTP_PROJECT_KEY: adyen-integration-test + CTP_PROJECT_KEY: adyen-integration-demo ingress: annotations: From 9e8f5a31f1d9403d7baba4b5be5e11f63d2dc12d Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Fri, 29 Mar 2019 15:18:49 +0100 Subject: [PATCH 13/30] send timestamp properly --- notification/src/handler/notification/notification.handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/notification/src/handler/notification/notification.handler.js b/notification/src/handler/notification/notification.handler.js index 48b4fcf41..cf7f28d70 100644 --- a/notification/src/handler/notification/notification.handler.js +++ b/notification/src/handler/notification/notification.handler.js @@ -99,7 +99,7 @@ function getAddInterfaceInteractionUpdateAction (notification) { typeId: 'type' }, fields: { - timestamp: new Date(), + timestamp: new Date().toISOString(), status: notification.NotificationRequestItem.eventCode, notification: JSON.stringify(notification) } From 3c31dbeb0b328ff2427ea815393375c7fac63da5 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Fri, 29 Mar 2019 16:26:27 +0100 Subject: [PATCH 14/30] improve logging --- .../payment-interface-interaction-type.json | 55 ++++++++++++++++++ .../payment-interface-interaction-types.json | 57 ------------------- ...nsure-interface-interaction-custom-type.js | 20 +++---- notification/src/init.js | 3 +- notification/src/server.js | 2 +- 5 files changed, 68 insertions(+), 69 deletions(-) create mode 100644 notification/resources/payment-interface-interaction-type.json delete mode 100644 notification/resources/payment-interface-interaction-types.json diff --git a/notification/resources/payment-interface-interaction-type.json b/notification/resources/payment-interface-interaction-type.json new file mode 100644 index 000000000..8ad7e1997 --- /dev/null +++ b/notification/resources/payment-interface-interaction-type.json @@ -0,0 +1,55 @@ +{ + "key": "ctp-adyen-integration-interaction-notification", + "name": { + "en": "ctp-adyen-integration-interaction-notification" + }, + "resourceTypeIds": [ + "payment-interface-interaction" + ], + "fieldDefinitions": [ + { + "name": "timestamp", + "label": { + "en": "timestamp" + }, + "required": true, + "type": { + "name": "String" + }, + "inputHint": "SingleLine" + }, + { + "name": "transactionId", + "label": { + "en": "transactionId" + }, + "required": false, + "type": { + "name": "String" + }, + "inputHint": "SingleLine" + }, + { + "name": "notification", + "label": { + "en": "notification" + }, + "required": true, + "type": { + "name": "String" + }, + "inputHint": "MultiLine" + }, + { + "name": "status", + "label": { + "en": "status" + }, + "required": false, + "type": { + "name": "String" + }, + "inputHint": "SingleLine" + } + ] +} diff --git a/notification/resources/payment-interface-interaction-types.json b/notification/resources/payment-interface-interaction-types.json deleted file mode 100644 index b24e86b6f..000000000 --- a/notification/resources/payment-interface-interaction-types.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "key": "ctp-adyen-integration-interaction-notification", - "name": { - "en": "ctp-adyen-integration-interaction-notification" - }, - "resourceTypeIds": [ - "payment-interface-interaction" - ], - "fieldDefinitions": [ - { - "name": "timestamp", - "label": { - "en": "timestamp" - }, - "required": true, - "type": { - "name": "String" - }, - "inputHint": "SingleLine" - }, - { - "name": "transactionId", - "label": { - "en": "transactionId" - }, - "required": false, - "type": { - "name": "String" - }, - "inputHint": "SingleLine" - }, - { - "name": "notification", - "label": { - "en": "notification" - }, - "required": true, - "type": { - "name": "String" - }, - "inputHint": "MultiLine" - }, - { - "name": "status", - "label": { - "en": "status" - }, - "required": false, - "type": { - "name": "String" - }, - "inputHint": "SingleLine" - } - ] - } -] diff --git a/notification/src/config/init/ensure-interface-interaction-custom-type.js b/notification/src/config/init/ensure-interface-interaction-custom-type.js index a9e54f59b..c35dd29d2 100644 --- a/notification/src/config/init/ensure-interface-interaction-custom-type.js +++ b/notification/src/config/init/ensure-interface-interaction-custom-type.js @@ -1,17 +1,17 @@ -const Promise = require('bluebird') +const logger = require('../../utils/logger').getLogger() -const interfaceInteractionTypes = require('../../../resources/payment-interface-interaction-types.json') +const interfaceInteractionType = require('../../../resources/payment-interface-interaction-type.json') async function ensureInterfaceInteractionCustomType (ctpClient) { - await Promise.map(interfaceInteractionTypes, async (type) => { - try { - const { body } = await ctpClient.fetch(ctpClient.builder.types.where(`key="${type.key}"`)) - if (body.results.length === 0) - await ctpClient.create(ctpClient.builder.types, type) - } catch (e) { - console.error('Error when creating interface interaction custom type, skipping...', JSON.stringify(e)) + try { + const { body } = await ctpClient.fetch(ctpClient.builder.types.where(`key="${interfaceInteractionType.key}"`)) + if (body.results.length === 0) { + await ctpClient.create(ctpClient.builder.types, interfaceInteractionType) + logger.info('Successfully created an interfaceInteraction type') } - }, { concurrency: 3 }) + } catch (e) { + logger.error('Error when creating interface interaction custom type, skipping...', JSON.stringify(e)) + } } module.exports = { diff --git a/notification/src/init.js b/notification/src/init.js index 67e575ba5..544bfb28f 100644 --- a/notification/src/init.js +++ b/notification/src/init.js @@ -2,11 +2,12 @@ const server = require('./server.js').setupServer() const { ensureInterfaceInteractionCustomType } = require('./config/init/ensure-interface-interaction-custom-type') const ctp = require('./utils/ctp') const config = require('./config/config')() +const logger = require('./utils/logger').getLogger(config.logLevel) const ctpClient = ctp.get(config) const PORT = process.env.PORT || 443 server.listen(PORT, async () => { await ensureInterfaceInteractionCustomType(ctpClient) - console.log(`Server running at http://127.0.0.1:${PORT}/`) + logger.info(`Server started on ${PORT} port`) }) diff --git a/notification/src/server.js b/notification/src/server.js index f5af134a1..1c643438a 100644 --- a/notification/src/server.js +++ b/notification/src/server.js @@ -1,9 +1,9 @@ const http = require('http') const url = require('url') const utils = require('./utils/commons') -const logger = require('./utils/logger').getLogger() const { routes: defaultRoutes } = require('./routes') require('./config/config') +const logger = require('./utils/logger').getLogger() function setupServer (routes = defaultRoutes) { From 7cf94b197d6597907d78bba22e2bd4d9f3a8e356 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Fri, 29 Mar 2019 16:36:54 +0100 Subject: [PATCH 15/30] #43 update secrets to right value --- extension/k8s/demo/secrets.yaml.enc | Bin 369 -> 366 bytes extension/k8s/values.yaml | 10 ------- .../src/config/init/ensure-api-extensions.js | 8 +++-- ...nsure-interface-interaction-custom-type.js | 9 ++++-- .../config/init/ensure-payment-custom-type.js | 10 +++++-- .../credit-card-complete-payment.handler.js | 2 +- extension/src/paymentHandler/payment-utils.js | 2 +- .../paypal/paypal-complete-payment.handler.js | 3 +- .../test/unit/payment.controller.spec.js | 28 +++--------------- 9 files changed, 28 insertions(+), 44 deletions(-) diff --git a/extension/k8s/demo/secrets.yaml.enc b/extension/k8s/demo/secrets.yaml.enc index 00093b3c6cb1f9c95d46eb34206d79a63bf9509d..5fe1f8c0e8a6cc3e9f5a9e2a7edccc2ddb67fd84 100644 GIT binary patch literal 366 zcmV-!0g?U+Bmix$qytYF#aNV~h0UX)<#s>e;tx~Aol$F?&BBijG~$6t^Ag1Z0BD@d z_}Sd4oV(*O%N(XX1Q(VMPSE0n4;N#pu;DYE*%?bK)tVL+wr;-g#M=LurN+Z(h@XLd zp1eZq94I2f5?dZnVJ%HOI{&MCS+>5~p!&#L1qM{6Ge>VWJNXyO<1J$ARd~BJnRWvZ z1WwVm*awVu><>rm3HB5@%t?)C3;Es@ MIU)<5ZQlTpn7GBV>Hq)$ literal 369 zcmV-%0gnC(Bmix$qywt;g)S4XR5HI%FpV#iRVYTSyv`taCL3fBJ+`Ho;}XaM0BD@d z_+Ooy-3^O6LPT3X){KZ>$LkNeB|6W z4ERAS3Rr9 zm9_>9vRbnwE|P;q%dY;>7-KrbhppM3LuZ+8ROB4QBu-&_^$pB_?0Ce$ne^)yFekOB zn-G5Wa^Fa=*a#almou6+o;XSFXR!3V1aLYElXCdoR4RuJvXxZ%hr-lQ1gI_ za}n`+T-v**LN-iotVd6%tQ~Y@;mZBw>UtroV|7`uI25Ffl!8)P2ndLr(SJMdBRrzl zkK!!wo05~5zwENM?OI<-b9db+AlV~bpoekj PPAvRSSLpES>Mcvgsf@O6 diff --git a/extension/k8s/values.yaml b/extension/k8s/values.yaml index 8e3b391c2..96b1b77e8 100644 --- a/extension/k8s/values.yaml +++ b/extension/k8s/values.yaml @@ -12,16 +12,6 @@ service: # https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ # https://cloud.google.com/compute/docs/machine-types -# When the pod is scheduled, the container is guaranteed the amount of resources requested 2GiB RAM and 300m CPU time and it is not allowed to exceed 2GB RAM and 300m of CPU time. -# This classifies the pod as "Guaranteed" -resources: - requests: - cpu: '300m' #30% of CPU time on 1 GCP Core - memory: '1Gi' #equivalent to 2GiB - limits: - cpu: '300m' #30% of CPU time on 1 GCP Core - memory: '1Gi' #equivalent to 2GB - ingress: enabled: true annotations: diff --git a/extension/src/config/init/ensure-api-extensions.js b/extension/src/config/init/ensure-api-extensions.js index ec22d36f9..e16abfba0 100644 --- a/extension/src/config/init/ensure-api-extensions.js +++ b/extension/src/config/init/ensure-api-extensions.js @@ -1,15 +1,19 @@ const _ = require('lodash') +const utils = require('../../utils') const apiExtensionTemplate = require('../../../resources/api-extension.json') +const logger = utils.getLogger() async function ensureApiExtensions (ctpClient, ctpAdyenIntegrationBaseUrl) { try { const extensionDraft = _.template(JSON.stringify(apiExtensionTemplate))({ ctpAdyenIntegrationBaseUrl }) const { body } = await ctpClient.fetch(ctpClient.builder.extensions.where(`key="${apiExtensionTemplate.key}"`)) - if (body.results.length === 0) + if (body.results.length === 0) { await ctpClient.create(ctpClient.builder.extensions, extensionDraft) + logger.info('Successfully created api extension') + } } catch (e) { - console.error('Error when creating API extension, skipping...', JSON.stringify(e)) + logger.error('Error when creating api extension, skipping...', JSON.stringify(e)) } } diff --git a/extension/src/config/init/ensure-interface-interaction-custom-type.js b/extension/src/config/init/ensure-interface-interaction-custom-type.js index a9e54f59b..14a1a65af 100644 --- a/extension/src/config/init/ensure-interface-interaction-custom-type.js +++ b/extension/src/config/init/ensure-interface-interaction-custom-type.js @@ -1,15 +1,20 @@ const Promise = require('bluebird') +const utils = require('../../utils') const interfaceInteractionTypes = require('../../../resources/payment-interface-interaction-types.json') +const logger = utils.getLogger() + async function ensureInterfaceInteractionCustomType (ctpClient) { await Promise.map(interfaceInteractionTypes, async (type) => { try { const { body } = await ctpClient.fetch(ctpClient.builder.types.where(`key="${type.key}"`)) - if (body.results.length === 0) + if (body.results.length === 0) { await ctpClient.create(ctpClient.builder.types, type) + logger.info('Successfully created an interfaceInteraction type') + } } catch (e) { - console.error('Error when creating interface interaction custom type, skipping...', JSON.stringify(e)) + logger.error('Error when creating interface interaction custom type, skipping...', JSON.stringify(e)) } }, { concurrency: 3 }) } diff --git a/extension/src/config/init/ensure-payment-custom-type.js b/extension/src/config/init/ensure-payment-custom-type.js index 1d2f69efe..33a7bf96b 100644 --- a/extension/src/config/init/ensure-payment-custom-type.js +++ b/extension/src/config/init/ensure-payment-custom-type.js @@ -1,12 +1,18 @@ const paymentCustomType = require('../../../resources/payment-custom-types.json') +const utils = require('../../utils') + +const logger = utils.getLogger() + async function ensurePaymentCustomType (ctpClient) { try { const { body } = await ctpClient.fetch(ctpClient.builder.types.where(`key="${paymentCustomType.key}"`)) - if (body.results.length === 0) + if (body.results.length === 0) { await ctpClient.create(ctpClient.builder.types, paymentCustomType) + logger.info('Successfully created payment custom type') + } } catch (e) { - console.error('Error when creating payment custom type, skipping...', JSON.stringify(e)) + logger.error('Error when creating payment custom type, skipping...', JSON.stringify(e)) } } diff --git a/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js b/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js index 201ae57e6..3ce263b66 100644 --- a/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js +++ b/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js @@ -11,7 +11,7 @@ const config = configLoader.load() async function handlePayment (paymentObject) { const validator = _validatePayment(paymentObject) if (validator.hasErrors()) - return validator.buildCtpErrorResponse() + return {} const { response, request } = await _completePayment(paymentObject) const status = response.status === 200 ? c.SUCCESS : c.FAILURE const responseBody = await response.json() diff --git a/extension/src/paymentHandler/payment-utils.js b/extension/src/paymentHandler/payment-utils.js index d667147ba..46bfeedb4 100644 --- a/extension/src/paymentHandler/payment-utils.js +++ b/extension/src/paymentHandler/payment-utils.js @@ -48,7 +48,7 @@ function createAddInterfaceInteractionAction ( action: 'addInterfaceInteraction', type: { key: c.CTP_INTERFACE_INTERACTION }, fields: { - timestamp: new Date(), + timestamp: new Date().toISOString(), response: JSON.stringify(response), request: JSON.stringify(request), type, diff --git a/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js b/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js index ee89faf8a..8c3853749 100644 --- a/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js +++ b/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js @@ -11,8 +11,7 @@ const config = configLoader.load() async function handlePayment (paymentObject) { const validator = _validatePayment(paymentObject) if (validator.hasErrors()) - return validator.buildCtpErrorResponse() - + return {} const { response, request } = await _callAdyen(paymentObject) const status = response.status === 200 ? c.SUCCESS : c.FAILURE const responseBody = await response.json() diff --git a/extension/test/unit/payment.controller.spec.js b/extension/test/unit/payment.controller.spec.js index 38a303d68..69802f2f6 100644 --- a/extension/test/unit/payment.controller.spec.js +++ b/extension/test/unit/payment.controller.spec.js @@ -91,13 +91,8 @@ describe('Payment controller', () => { utilsStub.collectRequestData = () => JSON.stringify({ resource: { obj: ctpPaymentClone } }) utilsStub.sendResponse = ({ statusCode, data }) => { - expect(statusCode).to.equal(400) - expect(data).to.deep.equal({ - errors: [{ - code: 'InvalidField', - message: errorMessages.MISSING_PAYLOAD - }] - }) + expect(statusCode).to.equal(200) + expect(data).to.deep.equal({}) } await paymentController.processRequest(mockRequest) @@ -185,23 +180,8 @@ describe('Payment controller', () => { utilsStub.collectRequestData = () => JSON.stringify({ resource: { obj: ctpPaymentClone } }) utilsStub.sendResponse = ({ statusCode, data }) => { - expect(statusCode).to.equal(400) - expect(data).to.deep.equal({ - errors: [ - { - code: 'InvalidField', - message: errorMessages.MISSING_PAYMENT_DATA - }, - { - code: 'InvalidField', - message: errorMessages.MISSING_MD - }, - { - code: 'InvalidField', - message: errorMessages.MISSING_PARES - } - ] - }) + expect(statusCode).to.equal(200) + expect(data).to.deep.equal({}) } await paymentController.processRequest(mockRequest) }) From 54ffcac53ca9bc6bb76a77b18d1ef662c80cad8e Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Fri, 29 Mar 2019 17:15:28 +0100 Subject: [PATCH 16/30] refactor logger --- .../config/init/ensure-interface-interaction-custom-type.js | 2 ++ notification/src/init.js | 2 +- notification/src/utils/logger.js | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/notification/src/config/init/ensure-interface-interaction-custom-type.js b/notification/src/config/init/ensure-interface-interaction-custom-type.js index c35dd29d2..fa04a76e0 100644 --- a/notification/src/config/init/ensure-interface-interaction-custom-type.js +++ b/notification/src/config/init/ensure-interface-interaction-custom-type.js @@ -4,8 +4,10 @@ const interfaceInteractionType = require('../../../resources/payment-interface-i async function ensureInterfaceInteractionCustomType (ctpClient) { try { + logger.debug('Ensuring interfaceInteraction') const { body } = await ctpClient.fetch(ctpClient.builder.types.where(`key="${interfaceInteractionType.key}"`)) if (body.results.length === 0) { + logger.debug('Creating interface interaction') await ctpClient.create(ctpClient.builder.types, interfaceInteractionType) logger.info('Successfully created an interfaceInteraction type') } diff --git a/notification/src/init.js b/notification/src/init.js index 544bfb28f..95a7efb41 100644 --- a/notification/src/init.js +++ b/notification/src/init.js @@ -1,8 +1,8 @@ const server = require('./server.js').setupServer() const { ensureInterfaceInteractionCustomType } = require('./config/init/ensure-interface-interaction-custom-type') const ctp = require('./utils/ctp') +const logger = require('./utils/logger').getLogger() const config = require('./config/config')() -const logger = require('./utils/logger').getLogger(config.logLevel) const ctpClient = ctp.get(config) const PORT = process.env.PORT || 443 diff --git a/notification/src/utils/logger.js b/notification/src/utils/logger.js index 199836665..0e28dc0b8 100644 --- a/notification/src/utils/logger.js +++ b/notification/src/utils/logger.js @@ -1,12 +1,13 @@ const bunyan = require('bunyan') +const { logLevel } = require('../config/config')() let obj -function getLogger (logLevel) { +function getLogger () { if( obj === undefined ) { const NOTIFICATION_MODULE_NAME = 'ctp-adyen-integration-notifications' obj = bunyan.createLogger({ name: NOTIFICATION_MODULE_NAME, - stream: process.stderr, + stream: process.stdout, level: logLevel || bunyan.ERROR }) } From a78da6327cb881067feee1cb77712fdc40831191 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Fri, 29 Mar 2019 17:56:08 +0100 Subject: [PATCH 17/30] #43 return update actions in a correct format --- extension/src/init.js | 5 +++-- .../creditCard/credit-card-complete-payment.handler.js | 5 +++-- .../creditCard/credit-card-make-payment.handler.js | 1 - .../src/paymentHandler/fetch-payment-methods.handler.js | 1 - .../src/paymentHandler/kcp/kcp-make-payment.handler.js | 1 - .../paypal/paypal-complete-payment.handler.js | 5 +++-- .../paymentHandler/paypal/paypal-make-payment.handler.js | 1 - extension/src/server.js | 1 - extension/src/utils.js | 6 ++++-- extension/test/unit/payment.controller.spec.js | 4 ++-- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/extension/src/init.js b/extension/src/init.js index be1010774..4f5956ea8 100644 --- a/extension/src/init.js +++ b/extension/src/init.js @@ -1,11 +1,12 @@ const init = require('./server.js').setupServer() -require('./config/config') +const utils = require('./utils') const { ensureResources } = require('./config/init/ensure-resources') const port = parseInt(process.env.EXTENSION_PORT || 8080, 10) +const logger = utils.getLogger() init.listen(port, async () => { await ensureResources() - console.log(`Server running at http://127.0.0.1:${port}/`) + logger.info(`Server running at http://127.0.0.1:${port}/`) }) diff --git a/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js b/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js index 3ce263b66..31c763b1c 100644 --- a/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js +++ b/extension/src/paymentHandler/creditCard/credit-card-complete-payment.handler.js @@ -11,7 +11,9 @@ const config = configLoader.load() async function handlePayment (paymentObject) { const validator = _validatePayment(paymentObject) if (validator.hasErrors()) - return {} + return { + actions: [] + } const { response, request } = await _completePayment(paymentObject) const status = response.status === 200 ? c.SUCCESS : c.FAILURE const responseBody = await response.json() @@ -35,7 +37,6 @@ async function handlePayment (paymentObject) { actions = _.compact(actions) return { - version: paymentObject.version, actions } } diff --git a/extension/src/paymentHandler/creditCard/credit-card-make-payment.handler.js b/extension/src/paymentHandler/creditCard/credit-card-make-payment.handler.js index 4cef68174..b3b6bb81a 100644 --- a/extension/src/paymentHandler/creditCard/credit-card-make-payment.handler.js +++ b/extension/src/paymentHandler/creditCard/credit-card-make-payment.handler.js @@ -65,7 +65,6 @@ async function handlePayment (paymentObject) { actions = _.compact(actions) return { - version: paymentObject.version, actions } } diff --git a/extension/src/paymentHandler/fetch-payment-methods.handler.js b/extension/src/paymentHandler/fetch-payment-methods.handler.js index c1cffe9de..4305e5cdd 100644 --- a/extension/src/paymentHandler/fetch-payment-methods.handler.js +++ b/extension/src/paymentHandler/fetch-payment-methods.handler.js @@ -8,7 +8,6 @@ async function handlePayment (paymentObject) { const { request, response } = await _fetchPaymentMethods(paymentObject) const responseBody = await response.json() return { - version: paymentObject.version, actions: [ pU.createAddInterfaceInteractionAction({ request, response: responseBody, type: 'getAvailablePaymentMethods' diff --git a/extension/src/paymentHandler/kcp/kcp-make-payment.handler.js b/extension/src/paymentHandler/kcp/kcp-make-payment.handler.js index 74fbbf8bd..ef99b42ec 100644 --- a/extension/src/paymentHandler/kcp/kcp-make-payment.handler.js +++ b/extension/src/paymentHandler/kcp/kcp-make-payment.handler.js @@ -39,7 +39,6 @@ async function handlePayment (paymentObject) { actions = _.compact(actions) return { - version: paymentObject.version, actions } } diff --git a/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js b/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js index 8c3853749..162f06fb3 100644 --- a/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js +++ b/extension/src/paymentHandler/paypal/paypal-complete-payment.handler.js @@ -11,7 +11,9 @@ const config = configLoader.load() async function handlePayment (paymentObject) { const validator = _validatePayment(paymentObject) if (validator.hasErrors()) - return {} + return { + actions: [] + } const { response, request } = await _callAdyen(paymentObject) const status = response.status === 200 ? c.SUCCESS : c.FAILURE const responseBody = await response.json() @@ -35,7 +37,6 @@ async function handlePayment (paymentObject) { actions = _.compact(actions) return { - version: paymentObject.version, actions } } diff --git a/extension/src/paymentHandler/paypal/paypal-make-payment.handler.js b/extension/src/paymentHandler/paypal/paypal-make-payment.handler.js index 089e3218d..9f09c26dc 100644 --- a/extension/src/paymentHandler/paypal/paypal-make-payment.handler.js +++ b/extension/src/paymentHandler/paypal/paypal-make-payment.handler.js @@ -39,7 +39,6 @@ async function handlePayment (paymentObject) { actions = _.compact(actions) return { - version: paymentObject.version, actions } } diff --git a/extension/src/server.js b/extension/src/server.js index 3f7450470..62828e4aa 100644 --- a/extension/src/server.js +++ b/extension/src/server.js @@ -2,7 +2,6 @@ const http = require('http') const url = require('url') const utils = require('./utils') const { routes: defaultRoutes } = require('./routes') -require('./config/config') const logger = utils.getLogger() diff --git a/extension/src/utils.js b/extension/src/utils.js index 9a930e446..3d2f69500 100644 --- a/extension/src/utils.js +++ b/extension/src/utils.js @@ -1,4 +1,6 @@ const bunyan = require('bunyan') +const configLoader = require('./config/config') +const config = configLoader.load() let logger @@ -23,12 +25,12 @@ function sendResponse ({ response.end(JSON.stringify(data)) } -function getLogger (logLevel) { +function getLogger () { if (!logger) logger = bunyan.createLogger({ name: 'ctp-adyen-integration-extension', stream: process.stderr, - level: logLevel || bunyan.ERROR + level: config.logLevel || bunyan.ERROR }) return logger } diff --git a/extension/test/unit/payment.controller.spec.js b/extension/test/unit/payment.controller.spec.js index 69802f2f6..151bf351b 100644 --- a/extension/test/unit/payment.controller.spec.js +++ b/extension/test/unit/payment.controller.spec.js @@ -92,7 +92,7 @@ describe('Payment controller', () => { utilsStub.collectRequestData = () => JSON.stringify({ resource: { obj: ctpPaymentClone } }) utilsStub.sendResponse = ({ statusCode, data }) => { expect(statusCode).to.equal(200) - expect(data).to.deep.equal({}) + expect(data).to.deep.equal({ actions: [] }) } await paymentController.processRequest(mockRequest) @@ -181,7 +181,7 @@ describe('Payment controller', () => { utilsStub.collectRequestData = () => JSON.stringify({ resource: { obj: ctpPaymentClone } }) utilsStub.sendResponse = ({ statusCode, data }) => { expect(statusCode).to.equal(200) - expect(data).to.deep.equal({}) + expect(data).to.deep.equal({ actions: [] }) } await paymentController.processRequest(mockRequest) }) From 8328096429891cb9ef9aae758489471543e41753 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Mon, 1 Apr 2019 11:54:01 +0200 Subject: [PATCH 18/30] #43 remove transaction validation --- extension/k8s/values.yaml | 2 +- .../src/paymentHandler/creditCard/credit-card.handler.js | 6 +----- extension/src/paymentHandler/kcp/kcp-payment.handler.js | 6 +----- extension/src/paymentHandler/paypal/paypal.handler.js | 6 +----- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/extension/k8s/values.yaml b/extension/k8s/values.yaml index 96b1b77e8..4ec5f0ac7 100644 --- a/extension/k8s/values.yaml +++ b/extension/k8s/values.yaml @@ -2,7 +2,7 @@ fullnameOverride: 'ctp-adyen-integration-service-extension' image: repository: 'eu.gcr.io/professionalserviceslabs/ctp-adyen-integration-extension' - tag: '1.0' + tag: '1.3' service: type: 'NodePort' diff --git a/extension/src/paymentHandler/creditCard/credit-card.handler.js b/extension/src/paymentHandler/creditCard/credit-card.handler.js index a1cd52263..47bd8b27a 100644 --- a/extension/src/paymentHandler/creditCard/credit-card.handler.js +++ b/extension/src/paymentHandler/creditCard/credit-card.handler.js @@ -4,7 +4,6 @@ const pU = require('../payment-utils') const creditCardMakePayment = require('./credit-card-make-payment.handler') const creditCardCompletePayment = require('./credit-card-complete-payment.handler') -const errorMessages = require('../../validator/error-messages') async function handlePayment (paymentObject) { const hasPendingTransaction = _.isObject(pU.getChargeTransactionPending(paymentObject)) @@ -14,10 +13,7 @@ async function handlePayment (paymentObject) { if (hasInitTransaction) return creditCardMakePayment.handlePayment(paymentObject) return { - errors: [{ - code: 'InvalidField', - message: errorMessages.MISSING_TXN_CHARGE_INIT_PENDING - }] + actions: [] } } diff --git a/extension/src/paymentHandler/kcp/kcp-payment.handler.js b/extension/src/paymentHandler/kcp/kcp-payment.handler.js index 1e87f23bd..35ac654e9 100644 --- a/extension/src/paymentHandler/kcp/kcp-payment.handler.js +++ b/extension/src/paymentHandler/kcp/kcp-payment.handler.js @@ -2,17 +2,13 @@ const _ = require('lodash') const pU = require('../payment-utils') const kcpMakePayment = require('./kcp-make-payment.handler') -const errorMessages = require('../../validator/error-messages') async function handlePayment (paymentObject) { const hasInitTransaction = _.isObject(pU.getChargeTransactionInit(paymentObject)) if (hasInitTransaction) return kcpMakePayment.handlePayment(paymentObject) return { - errors: [{ - code: 'InvalidField', - message: errorMessages.MISSING_TXN_CHARGE_INIT_PENDING - }] + actions: [] } } diff --git a/extension/src/paymentHandler/paypal/paypal.handler.js b/extension/src/paymentHandler/paypal/paypal.handler.js index 854c9b483..a8e477dc6 100644 --- a/extension/src/paymentHandler/paypal/paypal.handler.js +++ b/extension/src/paymentHandler/paypal/paypal.handler.js @@ -1,7 +1,6 @@ const _ = require('lodash') const pU = require('../payment-utils') -const errorMessages = require('../../validator/error-messages') const paypalMakePayment = require('./paypal-make-payment.handler') const paypalCompletePayment = require('./paypal-complete-payment.handler') @@ -14,10 +13,7 @@ async function handlePayment (paymentObject) { return paypalMakePayment.handlePayment(paymentObject) return { - errors: [{ - code: 'InvalidField', - message: errorMessages.MISSING_TXN_CHARGE_INIT_PENDING - }] + actions: [] } } From 879b4dee7e30bb790811760a7afa6d9663913512 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Mon, 1 Apr 2019 15:42:54 +0200 Subject: [PATCH 19/30] improve logging --- .../src/config/init/ensure-interface-interaction-custom-type.js | 2 +- notification/src/handler/notification/notification.handler.js | 2 ++ notification/src/utils/logger.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/notification/src/config/init/ensure-interface-interaction-custom-type.js b/notification/src/config/init/ensure-interface-interaction-custom-type.js index fa04a76e0..e87c4c67b 100644 --- a/notification/src/config/init/ensure-interface-interaction-custom-type.js +++ b/notification/src/config/init/ensure-interface-interaction-custom-type.js @@ -12,7 +12,7 @@ async function ensureInterfaceInteractionCustomType (ctpClient) { logger.info('Successfully created an interfaceInteraction type') } } catch (e) { - logger.error('Error when creating interface interaction custom type, skipping...', JSON.stringify(e)) + logger.error(e, 'Error when creating interface interaction custom type, skipping...') } } diff --git a/notification/src/handler/notification/notification.handler.js b/notification/src/handler/notification/notification.handler.js index cf7f28d70..0728ba445 100644 --- a/notification/src/handler/notification/notification.handler.js +++ b/notification/src/handler/notification/notification.handler.js @@ -37,6 +37,8 @@ async function updatePaymentWithRepeater (payment, notification, ctpClient) { try { /* eslint-disable-next-line no-await-in-loop */ await ctpClient.update(ctpClient.builder.payments, currentPayment.id, currentVersion, updateActions) + logger.debug(`Payment with interfaceId ${currentPayment.interfaceId}` + + 'was successfully updated') break } catch (err) { if (err.body.statusCode !== 409) diff --git a/notification/src/utils/logger.js b/notification/src/utils/logger.js index 0e28dc0b8..591f6f50a 100644 --- a/notification/src/utils/logger.js +++ b/notification/src/utils/logger.js @@ -8,7 +8,7 @@ function getLogger () { obj = bunyan.createLogger({ name: NOTIFICATION_MODULE_NAME, stream: process.stdout, - level: logLevel || bunyan.ERROR + level: logLevel || bunyan.INFO }) } return obj From 03717c80b0a5d67c14856045f377ad08eabd0ac9 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Mon, 1 Apr 2019 18:59:01 +0200 Subject: [PATCH 20/30] improve logging --- notification/src/api/notification/notification.controller.js | 4 ++-- notification/src/handler/notification/notification.handler.js | 4 ++-- notification/test/unit/notification.handler.spec.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/notification/src/api/notification/notification.controller.js b/notification/src/api/notification/notification.controller.js index 200ee5fd2..7664d6c07 100644 --- a/notification/src/api/notification/notification.controller.js +++ b/notification/src/api/notification/notification.controller.js @@ -19,8 +19,8 @@ async function handleNotification (request, response) { 200, { 'Content-Type': 'application/json' }, JSON.stringify({ notificationResponse: '[accepted]' })) - } catch (err) { - logger.error(err, 'Unexpected exception occurred') + } catch (e) { + logger.error(e, 'Unexpected exception occurred') return httpUtils.sendResponse(response, 500) } } diff --git a/notification/src/handler/notification/notification.handler.js b/notification/src/handler/notification/notification.handler.js index 0728ba445..7b3cd8513 100644 --- a/notification/src/handler/notification/notification.handler.js +++ b/notification/src/handler/notification/notification.handler.js @@ -40,7 +40,7 @@ async function updatePaymentWithRepeater (payment, notification, ctpClient) { logger.debug(`Payment with interfaceId ${currentPayment.interfaceId}` + 'was successfully updated') break - } catch (err) { + } catch (e) { if (err.body.statusCode !== 409) throw new Error(`Unexpected error during updating a payment with ID: ${currentPayment.id}. Exiting. ` + `Error: ${JSON.stringify(serializeError(err))}`) @@ -145,7 +145,7 @@ async function getPaymentByMerchantReference (merchantReference, ctpClient) { try { const result = await ctpClient.fetch(ctpClient.builder.payments.where(`interfaceId="${merchantReference}"`)) return _.get(result, 'body.results[0]', null) - } catch (err) { + } catch (e) { throw Error(`Failed to fetch a payment with merchantReference: ${merchantReference}. ` + `Error: ${JSON.stringify(serializeError(err))}`) } diff --git a/notification/test/unit/notification.handler.spec.js b/notification/test/unit/notification.handler.spec.js index fdfe02665..ea11cbdb0 100644 --- a/notification/test/unit/notification.handler.spec.js +++ b/notification/test/unit/notification.handler.spec.js @@ -228,7 +228,7 @@ describe('notification module', () => { }) try { await notificationHandler.processNotifications(notificationsMock, ctpClient) - } catch { + } catch (e) { } expect(ctpClientUpdateSpy.callCount).to.equal(21) From 9cbef81ce2dd6a38f8f5a556a2966204496a57c8 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Mon, 1 Apr 2019 18:59:38 +0200 Subject: [PATCH 21/30] remove redundant text from gitignore --- .gitignore | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 67871fd0c..f700d7475 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -# Created by .ignore support plugin (hsz.mobi) -### Node template # Logs logs *.log @@ -21,4 +19,7 @@ node_modules/ .idea *.iml -secrets.yaml \ No newline at end of file +secrets.yaml + +# NYC test coverage +.nyc_output/ From 293e26c72a5adf83f9cb9c8bdd6c0811bc632833 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Mon, 1 Apr 2019 19:00:07 +0200 Subject: [PATCH 22/30] make the node version cloud function friendly --- .travis.yml | 4 ++-- notification/Dockerfile | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3bfa4b975..6f9c2f687 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,11 @@ language: node_js node_js: - - '10' + - '8' env: - TEST_DIR=notification - TEST_DIR=extension before_install: - - npm i -g npm@^6.9.0 + - npm i -g npm@^6.4.1 before_cache: # because travis makes cache before calling "after_success" section we must install gcloud SDK here - $CI_SCRIPTS/gcloud-install-sdk.sh || travis_terminate 1 diff --git a/notification/Dockerfile b/notification/Dockerfile index a4a26baa2..fa487c617 100644 --- a/notification/Dockerfile +++ b/notification/Dockerfile @@ -1,4 +1,4 @@ -FROM mhart/alpine-node:10 +FROM mhart/alpine-node:8 MAINTAINER Professional Services WORKDIR /app @@ -10,4 +10,4 @@ RUN apk --update add git COPY . /app RUN npm ci --only=prod -ENTRYPOINT ["npm", "run", "start"] \ No newline at end of file +ENTRYPOINT ["npm", "run", "start"] From 8a7fb8809579848d446a508c4aeb2b0770a88a45 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Tue, 9 Apr 2019 17:52:35 +0200 Subject: [PATCH 23/30] fix eslint issues --- notification/package-lock.json | 602 +++++++++++++++++- notification/package.json | 7 +- .../notification/notification.controller.js | 1 + notification/src/config/config.js | 2 +- .../notification/notification.handler.js | 23 +- notification/src/init.js | 1 + notification/src/utils/ctp.js | 2 +- notification/src/utils/logger.js | 3 +- .../test/integration/init/init-resources.js | 4 +- .../integration/integration-test-set-up.js | 1 - .../integration/notification.handler.spec.js | 30 +- notification/test/unit/ctp-client-mock.js | 17 +- .../test/unit/notification.handler.spec.js | 82 +-- 13 files changed, 684 insertions(+), 91 deletions(-) diff --git a/notification/package-lock.json b/notification/package-lock.json index f4f077907..a02f83e8a 100644 --- a/notification/package-lock.json +++ b/notification/package-lock.json @@ -268,24 +268,59 @@ "sprintf-js": "~1.0.2" } }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", "dev": true }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -409,6 +444,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -422,6 +463,12 @@ "which": "^1.2.9" } }, + "damerau-levenshtein": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "dev": true + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -446,6 +493,15 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -475,6 +531,46 @@ "nan": "^2.10.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -543,6 +639,170 @@ } } }, + "eslint-config-airbnb": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz", + "integrity": "sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^13.1.0", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4" + } + }, + "eslint-config-airbnb-base": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz", + "integrity": "sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==", + "dev": true, + "requires": { + "eslint-restricted-globals": "^0.1.1", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4" + } + }, + "eslint-config-commercetools": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-commercetools/-/eslint-config-commercetools-6.0.0.tgz", + "integrity": "sha1-Zx8jpe2LRBOZG46CPunCRCy0xFE=", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz", + "integrity": "sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", + "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", + "dev": true, + "requires": { + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.3.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "read-pkg-up": "^2.0.0", + "resolve": "^1.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz", + "integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==", + "dev": true, + "requires": { + "aria-query": "^3.0.0", + "array-includes": "^3.0.3", + "ast-types-flow": "^0.0.7", + "axobject-query": "^2.0.2", + "damerau-levenshtein": "^1.0.4", + "emoji-regex": "^7.0.2", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1" + } + }, + "eslint-plugin-react": { + "version": "7.12.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz", + "integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", + "jsx-ast-utils": "^2.0.1", + "object.fromentries": "^2.0.0", + "prop-types": "^15.6.2", + "resolve": "^1.9.0" + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, "eslint-utils": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", @@ -655,6 +915,15 @@ "object-assign": "^4.0.1" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, "flat-cache": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", @@ -673,6 +942,12 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -717,17 +992,38 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -823,6 +1119,24 @@ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", "dev": true }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -835,6 +1149,30 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -869,9 +1207,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -905,6 +1243,15 @@ "diff-match-patch": "^1.0.0" } }, + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "^3.0.3" + } + }, "just-extend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", @@ -921,6 +1268,28 @@ "type-check": "~0.3.2" } }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", @@ -967,6 +1336,15 @@ "integrity": "sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw==", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", @@ -1156,6 +1534,18 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "nyc": { "version": "13.3.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.3.0.tgz", @@ -2196,6 +2586,48 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", + "has": "^1.0.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2233,6 +2665,30 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "parent-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz", @@ -2242,6 +2698,21 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2259,6 +2730,12 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -2276,12 +2753,36 @@ } } }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "dev": true }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -2300,18 +2801,65 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "react-is": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", "dev": true }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2431,6 +2979,38 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -2456,6 +3036,12 @@ "ansi-regex": "^3.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -2553,6 +3139,16 @@ "punycode": "^2.1.0" } }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/notification/package.json b/notification/package.json index b3f15e47e..29bd0532f 100644 --- a/notification/package.json +++ b/notification/package.json @@ -51,6 +51,11 @@ "mocha": "^5.2.0", "chai": "^4.2.0", "nyc": "^13.3.0", - "ip": "^1.1.5" + "ip": "^1.1.5", + "eslint-config-airbnb": "^17.1.0", + "eslint-config-commercetools": "^6.0.0", + "eslint-plugin-jsx-a11y": "^6.2.1", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-react": "^7.12.4" } } diff --git a/notification/src/api/notification/notification.controller.js b/notification/src/api/notification/notification.controller.js index 7664d6c07..7446790a1 100644 --- a/notification/src/api/notification/notification.controller.js +++ b/notification/src/api/notification/notification.controller.js @@ -4,6 +4,7 @@ const ctp = require('../../utils/ctp') const { processNotifications } = require('../../handler/notification/notification.handler') const config = require('../../config/config')() const logger = require('../../utils/logger').getLogger() + const ctpClient = ctp.get(config) // TODO: add JSON schema validation: diff --git a/notification/src/config/config.js b/notification/src/config/config.js index ed07714a1..7ef1b7ab5 100644 --- a/notification/src/config/config.js +++ b/notification/src/config/config.js @@ -29,7 +29,7 @@ function getFileConfig () { return fileConfig } -module.exports = function load() { +module.exports = function load () { /** * Load configuration from several sources in this order (last has highest priority): * - default config diff --git a/notification/src/handler/notification/notification.handler.js b/notification/src/handler/notification/notification.handler.js index 7b3cd8513..67615ad31 100644 --- a/notification/src/handler/notification/notification.handler.js +++ b/notification/src/handler/notification/notification.handler.js @@ -37,22 +37,22 @@ async function updatePaymentWithRepeater (payment, notification, ctpClient) { try { /* eslint-disable-next-line no-await-in-loop */ await ctpClient.update(ctpClient.builder.payments, currentPayment.id, currentVersion, updateActions) - logger.debug(`Payment with interfaceId ${currentPayment.interfaceId}` + - 'was successfully updated') + logger.debug(`Payment with interfaceId ${currentPayment.interfaceId}` + + 'was successfully updated') break } catch (e) { - if (err.body.statusCode !== 409) + if (e.body.statusCode !== 409) throw new Error(`Unexpected error during updating a payment with ID: ${currentPayment.id}. Exiting. ` - + `Error: ${JSON.stringify(serializeError(err))}`) + + `Error: ${JSON.stringify(serializeError(e))}`) retryCount += 1 if (retryCount > maxRetry) { retryMessage = 'Got a concurrent modification error' + ` when updating payment with id "${currentPayment.id}".` + ` Version tried "${currentVersion}",` - + ` currentVersion: "${err.body.errors[0].currentVersion}".` + + ` currentVersion: "${e.body.errors[0].currentVersion}".` throw new Error(`${retryMessage} Won't retry again` + ` because of a reached limit ${maxRetry}` - + ` max retries. Error: ${JSON.stringify(serializeError(err))}`) + + ` max retries. Error: ${JSON.stringify(serializeError(e))}`) } /* eslint-disable-next-line no-await-in-loop */ currentPayment = await ctpClient.fetchById(ctpClient.builder.payments, currentPayment.id) @@ -75,7 +75,10 @@ function calculateUpdateActionsForPayment (payment, notification) { if (isNotificationInInterfaceInteraction === false) updateActions.push(getAddInterfaceInteractionUpdateAction(notification)) - const { transactionType, transactionState } = getTransactionTypeAndStateOrNull(notificationEventCode, notificationSuccess) + const { + transactionType, + transactionState + } = getTransactionTypeAndStateOrNull(notificationEventCode, notificationSuccess) if (transactionType !== null) { // if there is already a transaction with type `transactionType` then update its `transactionState` if necessary, // otherwise create a transaction with type `transactionType` and state `transactionState` @@ -117,8 +120,8 @@ function getChangeTransactionStateUpdateAction (transactionId, newTransactionSta } function getTransactionTypeAndStateOrNull (adyenEventCode, adyenEventSuccess) { - return _.find(adyenEvents, - adyenEvent => adyenEvent.eventCode === adyenEventCode && adyenEvent.success === adyenEventSuccess) + // eslint-disable-next-line max-len + return _.find(adyenEvents, adyenEvent => adyenEvent.eventCode === adyenEventCode && adyenEvent.success === adyenEventSuccess) || { eventCode: adyenEventCode, success: adyenEventSuccess, @@ -147,7 +150,7 @@ async function getPaymentByMerchantReference (merchantReference, ctpClient) { return _.get(result, 'body.results[0]', null) } catch (e) { throw Error(`Failed to fetch a payment with merchantReference: ${merchantReference}. ` - + `Error: ${JSON.stringify(serializeError(err))}`) + + `Error: ${JSON.stringify(serializeError(e))}`) } } diff --git a/notification/src/init.js b/notification/src/init.js index 95a7efb41..ca225ae74 100644 --- a/notification/src/init.js +++ b/notification/src/init.js @@ -3,6 +3,7 @@ const { ensureInterfaceInteractionCustomType } = require('./config/init/ensure-i const ctp = require('./utils/ctp') const logger = require('./utils/logger').getLogger() const config = require('./config/config')() + const ctpClient = ctp.get(config) const PORT = process.env.PORT || 443 diff --git a/notification/src/utils/ctp.js b/notification/src/utils/ctp.js index 89bae69a1..2f14523be 100644 --- a/notification/src/utils/ctp.js +++ b/notification/src/utils/ctp.js @@ -37,7 +37,7 @@ function createCtpClient ({ authMiddleware, httpMiddleware, queueMiddleware - ], + ] }) } diff --git a/notification/src/utils/logger.js b/notification/src/utils/logger.js index 591f6f50a..248178fcb 100644 --- a/notification/src/utils/logger.js +++ b/notification/src/utils/logger.js @@ -1,9 +1,10 @@ const bunyan = require('bunyan') const { logLevel } = require('../config/config')() + let obj function getLogger () { - if( obj === undefined ) { + if (obj === undefined) { const NOTIFICATION_MODULE_NAME = 'ctp-adyen-integration-notifications' obj = bunyan.createLogger({ name: NOTIFICATION_MODULE_NAME, diff --git a/notification/test/integration/init/init-resources.js b/notification/test/integration/init/init-resources.js index e77b2182c..abc32989d 100644 --- a/notification/test/integration/init/init-resources.js +++ b/notification/test/integration/init/init-resources.js @@ -1,4 +1,6 @@ -const { ensureInterfaceInteractionCustomType } = require('../../../src/config/init/ensure-interface-interaction-custom-type') +const { + ensureInterfaceInteractionCustomType +} = require('../../../src/config/init/ensure-interface-interaction-custom-type') const { ensurePayment } = require('./ensure-payment') async function ensureResources (ctpClient) { diff --git a/notification/test/integration/integration-test-set-up.js b/notification/test/integration/integration-test-set-up.js index 48bbb131c..192f12a5f 100644 --- a/notification/test/integration/integration-test-set-up.js +++ b/notification/test/integration/integration-test-set-up.js @@ -11,7 +11,6 @@ async function prepareProject (ctpClient) { async function startServer (testServerPort = 8000) { return new Promise(((resolve) => { server.listen(testServerPort, async () => { - console.log(`Server running at http://127.0.0.1:${testServerPort}/`) resolve() }) })) diff --git a/notification/test/integration/notification.handler.spec.js b/notification/test/integration/notification.handler.spec.js index b97180fc7..9f2bc1855 100644 --- a/notification/test/integration/notification.handler.spec.js +++ b/notification/test/integration/notification.handler.spec.js @@ -12,7 +12,7 @@ const notifications = require('../resources/notification') const localhostIp = address() describe('notification module', () => { - let ctpClient = ctpClientBuilder.get(config) + const ctpClient = ctpClientBuilder.get(config) before(async () => { await iTSetUp.startServer() @@ -31,7 +31,7 @@ describe('notification module', () => { }) it('should update the transaction state when receives a correct notification', async () => { - const { body: { results: [ paymentBefore ] }} = await ctpClient.fetch(ctpClient.builder.payments) + const { body: { results: [ paymentBefore ] } } = await ctpClient.fetch(ctpClient.builder.payments) expect(paymentBefore.transactions).to.have.lengthOf(1) expect(paymentBefore.transactions[0].type).to.equal('Authorization') expect(paymentBefore.transactions[0].state).to.equal('Initial') @@ -40,16 +40,16 @@ describe('notification module', () => { // Simulating a notification from Adyen const response = await fetch(`http://${localhostIp}:8000`, { method: 'post', - body: JSON.stringify(notifications), + body: JSON.stringify(notifications), headers: { 'Content-Type': 'application/json' }, }) - const status = response.status + const { status } = response const responseBody = await response.json() expect(responseBody).to.deep.equal({ notificationResponse: '[accepted]' }) expect(status).to.equal(200) - const { body: { results: [ paymentAfter ] }} = await ctpClient.fetch(ctpClient.builder.payments) + const { body: { results: [ paymentAfter ] } } = await ctpClient.fetch(ctpClient.builder.payments) expect(paymentAfter.transactions).to.have.lengthOf(1) expect(paymentAfter.transactions[0].type).to.equal('Authorization') expect(paymentAfter.transactions[0].state).to.equal('Success') @@ -58,9 +58,9 @@ describe('notification module', () => { expect(paymentAfter.interfaceInteractions[0].fields.notification).to.equal(JSON.stringify(notification)) }) - it('should not update transaction when the notification event ' + - 'is not mapped to any CTP payment state', async () => { - const { body: { results: [ paymentBefore ] }} = await ctpClient.fetch(ctpClient.builder.payments) + it('should not update transaction when the notification event ' + + 'is not mapped to any CTP payment state', async () => { + const { body: { results: [ paymentBefore ] } } = await ctpClient.fetch(ctpClient.builder.payments) expect(paymentBefore.transactions).to.have.lengthOf(1) expect(paymentBefore.transactions[0].type).to.equal('Authorization') expect(paymentBefore.transactions[0].state).to.equal('Initial') @@ -71,16 +71,16 @@ describe('notification module', () => { // Simulating a notification from Adyen const response = await fetch(`http://${localhostIp}:8000`, { method: 'post', - body: JSON.stringify(modifiedNotification), + body: JSON.stringify(modifiedNotification), headers: { 'Content-Type': 'application/json' }, }) - const status = response.status + const { status } = response const responseBody = await response.json() expect(responseBody).to.deep.equal({ notificationResponse: '[accepted]' }) expect(status).to.equal(200) - const { body: { results: [ paymentAfter ] }} = await ctpClient.fetch(ctpClient.builder.payments) + const { body: { results: [ paymentAfter ] } } = await ctpClient.fetch(ctpClient.builder.payments) expect(paymentAfter.transactions).to.have.lengthOf(1) expect(paymentAfter.transactions[0].type).to.equal('Authorization') expect(paymentAfter.transactions[0].state).to.equal('Initial') @@ -90,7 +90,7 @@ describe('notification module', () => { }) it('should response with success when payment does not exist on the platform', async () => { - const { body: { results: [ paymentBefore ] }} = await ctpClient.fetch(ctpClient.builder.payments) + const { body: { results: [ paymentBefore ] } } = await ctpClient.fetch(ctpClient.builder.payments) expect(paymentBefore.transactions).to.have.lengthOf(1) expect(paymentBefore.transactions[0].type).to.equal('Authorization') expect(paymentBefore.transactions[0].state).to.equal('Initial') @@ -101,16 +101,16 @@ describe('notification module', () => { // Simulating a notification from Adyen const response = await fetch(`http://${localhostIp}:8000`, { method: 'post', - body: JSON.stringify(modifiedNotification), + body: JSON.stringify(modifiedNotification), headers: { 'Content-Type': 'application/json' }, }) - const status = response.status + const { status } = response const responseBody = await response.json() expect(responseBody).to.deep.equal({ notificationResponse: '[accepted]' }) expect(status).to.equal(200) - const { body: { results: [ paymentAfter ] }} = await ctpClient.fetch(ctpClient.builder.payments) + const { body: { results: [ paymentAfter ] } } = await ctpClient.fetch(ctpClient.builder.payments) expect(paymentAfter.transactions).to.have.lengthOf(1) expect(paymentAfter.transactions[0].type).to.equal('Authorization') expect(paymentAfter.transactions[0].state).to.equal('Initial') diff --git a/notification/test/unit/ctp-client-mock.js b/notification/test/unit/ctp-client-mock.js index 72ec6f5b9..bb0a26b78 100644 --- a/notification/test/unit/ctp-client-mock.js +++ b/notification/test/unit/ctp-client-mock.js @@ -3,7 +3,6 @@ const { createClient } = require('@commercetools/sdk-client') const { createRequestBuilder } = require('@commercetools/api-request-builder') function createCtpClient () { - const httpMockSuccessMiddleware = next => (request, response) => { next(request, { ...response, body: { foo: 'bar' } }) } @@ -69,14 +68,14 @@ function getRequestBuilder (projectKey) { * */ function compareTransactionStates (currentState, newState) { const transactionStateFlow = { - "Initial": 0, - "Pending": 1, - "Success": 2, - "Failure": 2 + Initial: 0, + Pending: 1, + Success: 2, + Failure: 2 } - if(!transactionStateFlow.hasOwnProperty(currentState) || !transactionStateFlow.hasOwnProperty(newState)) - throw Error('Wrong transaction state passed. ' + - `currentState: ${currentState}, newState: ${newState}`) + if (!transactionStateFlow.hasOwnProperty(currentState) || !transactionStateFlow.hasOwnProperty(newState)) + throw Error('Wrong transaction state passed. ' + + `currentState: ${currentState}, newState: ${newState}`) if (transactionStateFlow[currentState] < transactionStateFlow[newState]) return 1 if (transactionStateFlow[currentState] > transactionStateFlow[newState]) @@ -86,6 +85,6 @@ function compareTransactionStates (currentState, newState) { module.exports = { - get: (config) => setUpClient(config), + get: config => setUpClient(config), compareTransactionStates } diff --git a/notification/test/unit/notification.handler.spec.js b/notification/test/unit/notification.handler.spec.js index ea11cbdb0..e9e26b5bb 100644 --- a/notification/test/unit/notification.handler.spec.js +++ b/notification/test/unit/notification.handler.spec.js @@ -18,21 +18,17 @@ const config = { } describe('notification module', () => { - afterEach(() => sandbox.restore()) it('should update payment with a new InterfaceInteraction and payment status ' + 'when current payment does not have the interfaceInteraction and the transaction' + 'which are going to be set', async () => { - const ctpClient = ctpClientMock.get(config) - sandbox.stub(ctpClient, 'fetch').callsFake(() => { - return { - body: { - results: [paymentMock] - } + sandbox.stub(ctpClient, 'fetch').callsFake(() => ({ + body: { + results: [paymentMock] } - }) + })) const ctpClientUpdateSpy = sandbox.spy(ctpClient, 'update') await notificationHandler.processNotifications(notificationsMock, ctpClient) const expectedUpdateActions = [ @@ -73,23 +69,21 @@ describe('notification module', () => { + 'but has a transaction with the correct status', async () => { const modifiedPaymentMock = cloneDeep(paymentMock) modifiedPaymentMock.transactions.push({ - "type": "Authorization", - "amount": { - "type": "centPrecision", - "currencyCode": "EUR", - "centAmount": 495, - "fractionDigits": 2 + type: 'Authorization', + amount: { + type: 'centPrecision', + currencyCode: 'EUR', + centAmount: 495, + fractionDigits: 2 }, - "state": "Success" + state: 'Success' }) const ctpClient = ctpClientMock.get(config) - sandbox.stub(ctpClient, 'fetch').callsFake(() => { - return { - body: { - results: [modifiedPaymentMock] - } + sandbox.stub(ctpClient, 'fetch').callsFake(() => ({ + body: { + results: [modifiedPaymentMock] } - }) + })) const ctpClientUpdateSpy = sandbox.spy(ctpClient, 'update') await notificationHandler.processNotifications(notificationsMock, ctpClient) const expectedUpdateActions = [ @@ -130,13 +124,11 @@ describe('notification module', () => { } }) const ctpClient = ctpClientMock.get(config) - sandbox.stub(ctpClient, 'fetch').callsFake(() => { - return { - body: { - results: [modifiedPaymentMock] - } + sandbox.stub(ctpClient, 'fetch').callsFake(() => ({ + body: { + results: [modifiedPaymentMock] } - }) + })) const ctpClientUpdateSpy = sandbox.spy(ctpClient, 'update') await notificationHandler.processNotifications(notificationsMock, ctpClient) const expectedUpdateActions = [ @@ -159,8 +151,8 @@ describe('notification module', () => { it('should update transaction with a new state', async () => { const modifiedPaymentMock = cloneDeep(paymentMock) const notificationsMockClone = cloneDeep(notificationsMock) - notificationsMockClone[0].NotificationRequestItem.eventCode = "CAPTURE" - notificationsMockClone[0].NotificationRequestItem.success = "false" + notificationsMockClone[0].NotificationRequestItem.eventCode = 'CAPTURE' + notificationsMockClone[0].NotificationRequestItem.success = 'false' modifiedPaymentMock.interfaceInteractions.push({ type: { typeId: 'type', @@ -173,13 +165,11 @@ describe('notification module', () => { } }) const ctpClient = ctpClientMock.get(config) - sandbox.stub(ctpClient, 'fetch').callsFake(() => { - return { - body: { - results: [modifiedPaymentMock] - } + sandbox.stub(ctpClient, 'fetch').callsFake(() => ({ + body: { + results: [modifiedPaymentMock] } - }) + })) const ctpClientUpdateSpy = sandbox.spy(ctpClient, 'update') @@ -209,27 +199,23 @@ describe('notification module', () => { } }) const ctpClient = ctpClientMock.get(config) - sandbox.stub(ctpClient, 'fetch').callsFake(() => { - return { - body: { - results: [modifiedPaymentMock] - } + sandbox.stub(ctpClient, 'fetch').callsFake(() => ({ + body: { + results: [modifiedPaymentMock] } - }) - sandbox.stub(ctpClient, 'fetchById').callsFake(() => { - return { - body: { - results: [modifiedPaymentMock] - } + })) + sandbox.stub(ctpClient, 'fetchById').callsFake(() => ({ + body: { + results: [modifiedPaymentMock] } - }) + })) const ctpClientUpdateSpy = sandbox.stub(ctpClient, 'update').callsFake(() => { throw concurrentModificationError }) try { await notificationHandler.processNotifications(notificationsMock, ctpClient) + // eslint-disable-next-line no-empty } catch (e) { - } expect(ctpClientUpdateSpy.callCount).to.equal(21) }) From 7e1038764e09cdb945f1db88b9abd0b677cc09d1 Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Tue, 16 Apr 2019 10:44:34 +0200 Subject: [PATCH 24/30] fix logging in the extension module --- extension/src/config/init/ensure-api-extensions.js | 2 +- .../src/config/init/ensure-interface-interaction-custom-type.js | 2 +- extension/src/config/init/ensure-payment-custom-type.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extension/src/config/init/ensure-api-extensions.js b/extension/src/config/init/ensure-api-extensions.js index e16abfba0..b8f5c9ff4 100644 --- a/extension/src/config/init/ensure-api-extensions.js +++ b/extension/src/config/init/ensure-api-extensions.js @@ -13,7 +13,7 @@ async function ensureApiExtensions (ctpClient, ctpAdyenIntegrationBaseUrl) { logger.info('Successfully created api extension') } } catch (e) { - logger.error('Error when creating api extension, skipping...', JSON.stringify(e)) + logger.error(e, 'Error when creating api extension, skipping...') } } diff --git a/extension/src/config/init/ensure-interface-interaction-custom-type.js b/extension/src/config/init/ensure-interface-interaction-custom-type.js index 14a1a65af..7f81c9e8e 100644 --- a/extension/src/config/init/ensure-interface-interaction-custom-type.js +++ b/extension/src/config/init/ensure-interface-interaction-custom-type.js @@ -14,7 +14,7 @@ async function ensureInterfaceInteractionCustomType (ctpClient) { logger.info('Successfully created an interfaceInteraction type') } } catch (e) { - logger.error('Error when creating interface interaction custom type, skipping...', JSON.stringify(e)) + logger.error(e, 'Error when creating interface interaction custom type, skipping...') } }, { concurrency: 3 }) } diff --git a/extension/src/config/init/ensure-payment-custom-type.js b/extension/src/config/init/ensure-payment-custom-type.js index 33a7bf96b..093ecfb6c 100644 --- a/extension/src/config/init/ensure-payment-custom-type.js +++ b/extension/src/config/init/ensure-payment-custom-type.js @@ -12,7 +12,7 @@ async function ensurePaymentCustomType (ctpClient) { logger.info('Successfully created payment custom type') } } catch (e) { - logger.error('Error when creating payment custom type, skipping...', JSON.stringify(e)) + logger.error(e, 'Error when creating payment custom type, skipping...') } } From 64192281d8717eb9cf7b7097794a3cdbe6c0038a Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Tue, 16 Apr 2019 14:13:55 +0200 Subject: [PATCH 25/30] change timestamp -> createdAt --- .../payment-interface-interaction-types.json | 8 +++--- extension/src/paymentHandler/payment-utils.js | 2 +- extension/test/fixtures/ctp-payment.json | 6 ++--- .../payment-interface-interaction-type.json | 6 ++--- .../notification/notification.handler.js | 2 +- .../test/unit/notification.handler.spec.js | 26 +++++++++---------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/extension/resources/payment-interface-interaction-types.json b/extension/resources/payment-interface-interaction-types.json index 56e91ef2f..58fff7390 100644 --- a/extension/resources/payment-interface-interaction-types.json +++ b/extension/resources/payment-interface-interaction-types.json @@ -9,13 +9,13 @@ ], "fieldDefinitions": [ { - "name": "timestamp", + "name": "createdAt", "label": { - "en": "timestamp" + "en": "createdAt" }, "required": true, "type": { - "name": "String" + "name": "DateTime" }, "inputHint": "SingleLine" }, @@ -76,4 +76,4 @@ } ] } -] \ No newline at end of file +] diff --git a/extension/src/paymentHandler/payment-utils.js b/extension/src/paymentHandler/payment-utils.js index 46bfeedb4..80da73774 100644 --- a/extension/src/paymentHandler/payment-utils.js +++ b/extension/src/paymentHandler/payment-utils.js @@ -48,7 +48,7 @@ function createAddInterfaceInteractionAction ( action: 'addInterfaceInteraction', type: { key: c.CTP_INTERFACE_INTERACTION }, fields: { - timestamp: new Date().toISOString(), + createdAt: new Date(), response: JSON.stringify(response), request: JSON.stringify(request), type, diff --git a/extension/test/fixtures/ctp-payment.json b/extension/test/fixtures/ctp-payment.json index 5f1643fd7..8ae8790bd 100644 --- a/extension/test/fixtures/ctp-payment.json +++ b/extension/test/fixtures/ctp-payment.json @@ -66,7 +66,7 @@ }, "fields": { "request": "request", - "timestamp": "2019-02-28T22:16:04.246Z", + "createdAt": "2019-02-28T22:16:04.246Z", "response": "response=", "status": "SUCCESS", "type": "makePayment" @@ -79,11 +79,11 @@ }, "fields": { "request": "request", - "timestamp": "2019-02-28T22:16:19.086Z", + "createdAt": "2019-02-28T22:16:19.086Z", "response": "response", "status": "SUCCESS", "type": "completePayment" } } ] -} \ No newline at end of file +} diff --git a/notification/resources/payment-interface-interaction-type.json b/notification/resources/payment-interface-interaction-type.json index 8ad7e1997..2a4625b2e 100644 --- a/notification/resources/payment-interface-interaction-type.json +++ b/notification/resources/payment-interface-interaction-type.json @@ -8,13 +8,13 @@ ], "fieldDefinitions": [ { - "name": "timestamp", + "name": "createdAt", "label": { - "en": "timestamp" + "en": "createdAt" }, "required": true, "type": { - "name": "String" + "name": "DateTime" }, "inputHint": "SingleLine" }, diff --git a/notification/src/handler/notification/notification.handler.js b/notification/src/handler/notification/notification.handler.js index 67615ad31..38cfc5d58 100644 --- a/notification/src/handler/notification/notification.handler.js +++ b/notification/src/handler/notification/notification.handler.js @@ -104,7 +104,7 @@ function getAddInterfaceInteractionUpdateAction (notification) { typeId: 'type' }, fields: { - timestamp: new Date().toISOString(), + createdAt: new Date(), status: notification.NotificationRequestItem.eventCode, notification: JSON.stringify(notification) } diff --git a/notification/test/unit/notification.handler.spec.js b/notification/test/unit/notification.handler.spec.js index 93d36f326..e2cf18727 100644 --- a/notification/test/unit/notification.handler.spec.js +++ b/notification/test/unit/notification.handler.spec.js @@ -56,12 +56,12 @@ describe('notification module', () => { } ] - // Timestamp is set to the current date during the update action calculation + // createdAt is set to the current date during the update action calculation // We can't know what is set there - expect(ctpClientUpdateSpy.args[0][3][0].fields.timestamp).to.exist - const actualUpdateActionsWithoutTimestamp = ctpClientUpdateSpy.args[0][3] - delete actualUpdateActionsWithoutTimestamp[0].fields.timestamp - expect(actualUpdateActionsWithoutTimestamp).to.deep.equal(expectedUpdateActions) + expect(ctpClientUpdateSpy.args[0][3][0].fields.createdAt).to.exist + const actualUpdateActionsWithoutCreatedAt = ctpClientUpdateSpy.args[0][3] + delete actualUpdateActionsWithoutCreatedAt[0].fields.createdAt + expect(actualUpdateActionsWithoutCreatedAt).to.deep.equal(expectedUpdateActions) }) it('should update payment with a new InterfaceInteraction but not payment status ' @@ -100,12 +100,12 @@ describe('notification module', () => { } ] - // Timestamp is set to the current date during the update action calculation + // createdAt is set to the current date during the update action calculation // We can't know what is set there - expect(ctpClientUpdateSpy.args[0][3][0].fields.timestamp).to.exist - const actualUpdateActionsWithoutTimestamp = ctpClientUpdateSpy.args[0][3] - delete actualUpdateActionsWithoutTimestamp[0].fields.timestamp - expect(actualUpdateActionsWithoutTimestamp).to.deep.equal(expectedUpdateActions) + expect(ctpClientUpdateSpy.args[0][3][0].fields.createdAt).to.exist + const actualUpdateActionsWithoutCreatedAt = ctpClientUpdateSpy.args[0][3] + delete actualUpdateActionsWithoutCreatedAt[0].fields.createdAt + expect(actualUpdateActionsWithoutCreatedAt).to.deep.equal(expectedUpdateActions) }) it('should update payment with a payment status but not new InterfaceInteraction ' @@ -120,7 +120,7 @@ describe('notification module', () => { fields: { notification: JSON.stringify(notificationsMock[0]), status: 'SUCCESS', - timestamp: '2019-02-05T12:29:36.028Z' + createdAt: '2019-02-05T12:29:36.028Z' } }) const ctpClient = ctpClientMock.get(config) @@ -159,7 +159,7 @@ describe('notification module', () => { id: '3fd15a04-b460-4a88-a911-0472c4c080b3' }, fields: { - timestamp: '2019-02-05T12:29:36.028Z', + createdAt: '2019-02-05T12:29:36.028Z', notification: JSON.stringify(notificationsMockClone[0]), status: 'SUCCESS' } @@ -193,7 +193,7 @@ describe('notification module', () => { id: '3fd15a04-b460-4a88-a911-0472c4c080b3' }, fields: { - timestamp: '2019-02-05T12:29:36.028Z', + createdAt: '2019-02-05T12:29:36.028Z', notification: JSON.stringify(notificationsMock[0]), status: 'SUCCESS' } From 5a00af7f8ba9016d3fa446bfff5031bdceb9516b Mon Sep 17 00:00:00 2001 From: Hasan Mammed-zadeh Date: Tue, 16 Apr 2019 14:30:15 +0200 Subject: [PATCH 26/30] add a comment on an empty catch block --- notification/test/unit/notification.handler.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notification/test/unit/notification.handler.spec.js b/notification/test/unit/notification.handler.spec.js index e2cf18727..2c25c0ca4 100644 --- a/notification/test/unit/notification.handler.spec.js +++ b/notification/test/unit/notification.handler.spec.js @@ -216,6 +216,8 @@ describe('notification module', () => { await notificationHandler.processNotifications(notificationsMock, ctpClient) // eslint-disable-next-line no-empty } catch (e) { + // we check retry logic here and it should throw after certain amount + // of retries. So the error is expected } expect(ctpClientUpdateSpy.callCount).to.equal(21) }) From d96731796b17f455d59d7befeea7161e6d1ea42b Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Tue, 16 Apr 2019 16:18:15 +0200 Subject: [PATCH 27/30] #43 add script for building docker image --- .travis.yml | 10 +- extension/k8s/crypt/crypt.sh | 148 ------------------------- extension/k8s/crypt/decrypt.sh | 28 ----- extension/k8s/crypt/encrypt.sh | 27 ----- extension/k8s/demo/secrets.yaml.enc | Bin 366 -> 0 bytes extension/k8s/demo/values.yaml | 12 -- extension/k8s/values.yaml | 28 ----- notification/k8s/crypt/crypt.sh | 148 ------------------------- notification/k8s/crypt/decrypt.sh | 28 ----- notification/k8s/crypt/encrypt.sh | 27 ----- notification/k8s/demo/secrets.yaml.enc | Bin 193 -> 0 bytes notification/k8s/demo/values.yaml | 9 -- notification/k8s/values.yaml | 40 ------- travis-build.sh | 17 +++ travis-build/common.sh | 22 ---- travis-build/gcloud-deploy.sh | 39 ------- travis-build/gcloud-install-sdk.sh | 30 ----- travis-build/gcloud-login.sh | 24 ---- travis-build/gcloud-push-image.sh | 29 ----- travis-build/helm-upgrade.sh | 27 ----- travis-build/k8s-charts-clone.sh | 13 --- 21 files changed, 24 insertions(+), 682 deletions(-) delete mode 100755 extension/k8s/crypt/crypt.sh delete mode 100755 extension/k8s/crypt/decrypt.sh delete mode 100644 extension/k8s/crypt/encrypt.sh delete mode 100644 extension/k8s/demo/secrets.yaml.enc delete mode 100644 extension/k8s/demo/values.yaml delete mode 100644 extension/k8s/values.yaml delete mode 100755 notification/k8s/crypt/crypt.sh delete mode 100755 notification/k8s/crypt/decrypt.sh delete mode 100644 notification/k8s/crypt/encrypt.sh delete mode 100644 notification/k8s/demo/secrets.yaml.enc delete mode 100644 notification/k8s/demo/values.yaml delete mode 100644 notification/k8s/values.yaml create mode 100755 travis-build.sh delete mode 100644 travis-build/common.sh delete mode 100755 travis-build/gcloud-deploy.sh delete mode 100755 travis-build/gcloud-install-sdk.sh delete mode 100755 travis-build/gcloud-login.sh delete mode 100755 travis-build/gcloud-push-image.sh delete mode 100755 travis-build/helm-upgrade.sh delete mode 100755 travis-build/k8s-charts-clone.sh diff --git a/.travis.yml b/.travis.yml index 6f9c2f687..f9b5975b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,6 @@ env: - TEST_DIR=extension before_install: - npm i -g npm@^6.4.1 -before_cache: - # because travis makes cache before calling "after_success" section we must install gcloud SDK here - - $CI_SCRIPTS/gcloud-install-sdk.sh || travis_terminate 1 services: - docker script: @@ -16,3 +13,10 @@ script: - npm ci - npm run test - if [ "$TEST_DIR" = "extension" ]; then npm run cypress; fi + +deploy: + - provider: script + script: bash ./travis-build.sh + on: + tags: true + condition: $TRAVIS_TAG =~ ^v[0-9]+.[0-9]+.[0-9]+ \ No newline at end of file diff --git a/extension/k8s/crypt/crypt.sh b/extension/k8s/crypt/crypt.sh deleted file mode 100755 index e684b3c01..000000000 --- a/extension/k8s/crypt/crypt.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -set -e - -declare -a ACTIONS=("encrypt" "decrypt") -declare -a ENVIRONMENTS=("demo") -# Google Cloud project -PROJECT_NAME="ctp-adyen-integration" -GCLOUD_PROJECT_ID="professionalserviceslabs" -SELECTED_APPLICATION="ctp-adyen-integration-extension" - -# Checks if the element exists in the array -# Usage: containsElement "${array[@]}" "blabla" -function containsElement() { - local n=$# - local value=${!n} - for ((i=1;i < $#;i++)) { - if [ "${!i}" == "${value}" ]; then - return 0 - fi - } - return 1 -} - -requireEnvironment(){ - printf "Available environments:\n" - for i in "${!ENVIRONMENTS[@]}" ; do - printf "> %s. %s\n" "$(($i+1))" "${ENVIRONMENTS[$i]}" - done - read -p "Enter the environment number: " SELECTED_ENVIRONMENT_INDEX - printf "\n" - # If the entered environment number is out of `ENVIRONMENTS` then exit - if ! [ "$SELECTED_ENVIRONMENT_INDEX" -ge 1 -a "$SELECTED_ENVIRONMENT_INDEX" -le ${#ENVIRONMENTS[@]} ]; then - printf "Wrong environment number. Exiting with 1.\n" - exit 1 - fi - # Workaround for return. Returns function parameter by reference - eval "$1='${ENVIRONMENTS[$(($SELECTED_ENVIRONMENT_INDEX-1))]}'" -} - -requireAction(){ - printf "Available actions:\n" - for i in "${!ACTIONS[@]}" ; do - printf "> %s. %s\n" "$(($i+1))" "${ACTIONS[$i]}" - done - read -p "Enter the action number: " SELECTED_ACTION_INDEX - printf "\n" - # If the entered action number is out of `ACTIONS` then exit - if ! [ "$SELECTED_ACTION_INDEX" -ge 1 -a "$SELECTED_ACTION_INDEX" -le ${#ACTIONS[@]} ]; then - printf "Wrong action number. Exiting with 1.\n" - exit 1 - fi - # Workaround for return. Returns function parameter by reference - eval "$1='${ACTIONS[$((SELECTED_ACTION_INDEX-1))]}'" -} - -includeScriptOrDie() { - COMMON_SCRIPT="$(dirname "$0")/$1" - if [ ! -r "$COMMON_SCRIPT" ] ; then - echo "Error: script [${COMMON_SCRIPT}] not found!" - exit 1 - fi - . "$COMMON_SCRIPT" -} - -# This function ensures that all necessary arguments are passed to the script. -# If no arguments passed - it asks all of them -# If only 1 argument passed - it asks for other 2 -# and so on. -# It also validates all passed arguments and returns in case of invalid one. -requireArguments() { - local ACTION_VALIDATION_ERROR_MESSAGE="Provided action is invalid." - local ENVIRONMENT_VALIDATION_ERROR_MESSAGE="Provided environment is invalid." - case "$#" in - "0") - requireAction SELECTED_ACTION - requireEnvironment SELECTED_ENVIRONMENT - requestApproval - ;; - "1") - if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@]; then - SELECTED_ACTION=$1; - else return 1 - fi - # requireApplication SELECTED_APPLICATION - requireEnvironment SELECTED_ENVIRONMENT - requestApproval - ;; - *) - if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@] && \ - # validateInput $2 "${APPLICATION_NAME_VALIDATION_ERROR_MESSAGE}" APPLICATION_NAMES[@] && \ - validateInput $2 "${ENVIRONMENT_VALIDATION_ERROR_MESSAGE}" ENVIRONMENTS[@] ; then - SELECTED_ACTION=$1 - # SELECTED_APPLICATION=$2 - SELECTED_ENVIRONMENT=$2 - else return 1 - fi - ;; - esac -} - -startEncrypt() { - includeScriptOrDie "encrypt.sh" - local ENCRYPTED_FILE='' - encrypt ENCRYPTED_FILE \ - && printf "Encrypted successfully:\n" \ - && ls -l ${ENCRYPTED_FILE} \ - && printf "Don't forget to add/commit the encrypted file\n" -} - -startDecrypt() { - local DECRYPTED_FILE='' - includeScriptOrDie "decrypt.sh" - decrypt DECRYPTED_FILE \ - && printf "\nDecrypted successfully:\n" \ - && ls -l ${DECRYPTED_FILE} -} - -requestApproval() { - while true; do - read -p "Going to execute`echo $'\n> '`${bold}${SELECTED_ACTION} ${SELECTED_APPLICATION} ${SELECTED_ENVIRONMENT} (y/n)${normal} " yn - case ${yn} in - [Yy]* ) echo "Starting to ${SELECTED_ACTION}..."; break;; - [Nn]* ) echo "Terminating process"; exit;; - * ) echo "Please answer yes or no.";; - esac - done -} - -main() { - local bold=$(tput bold) - local normal=$(tput sgr0) - requireArguments $@ || return 1 - - if [ "${SELECTED_ACTION}" = "encrypt" ] ; then - startEncrypt - else - startDecrypt - fi -} - -validateInput() { - if ! containsElement ${!3} "$1"; then - printf "$2\n" - return 1 - fi -} - -if ! main $@; then exit 1; fi \ No newline at end of file diff --git a/extension/k8s/crypt/decrypt.sh b/extension/k8s/crypt/decrypt.sh deleted file mode 100755 index d9ab037c4..000000000 --- a/extension/k8s/crypt/decrypt.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -set -e - -KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" -KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" - -ENC_EXT=".enc" -SECRETS_NAME="secrets.yaml" -DIR="$( cd "$( dirname "$0" )" && pwd )" -DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" -ENCRYPTED_FILE="${DECRYPTED_FILE}${ENC_EXT}" - -decrypt() { - if [ ! -f ${ENCRYPTED_FILE} ]; then - printf "Encrypted secret file not found!\n" - return 1 - fi - - gcloud kms decrypt \ - --project="${GCLOUD_PROJECT_ID}"\ - --location="global" \ - --keyring="$KEYRING" \ - --key="$KEY" \ - --plaintext-file="${DECRYPTED_FILE}" \ - --ciphertext-file="${ENCRYPTED_FILE}" - # Workaround for return. Returns function parameter by reference - eval "$1='${DECRYPTED_FILE}'" -} \ No newline at end of file diff --git a/extension/k8s/crypt/encrypt.sh b/extension/k8s/crypt/encrypt.sh deleted file mode 100644 index 130b803d3..000000000 --- a/extension/k8s/crypt/encrypt.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -set -e - -KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" -KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" - -ENC_EXT=".enc" -SECRETS_NAME="secrets.yaml" -DIR="$( cd "$( dirname "$0" )" && pwd )" -DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" - -encrypt() { - if [ ! -f ${DECRYPTED_FILE} ]; then - printf "Secret file not found!\n" - return 1 - fi - - gcloud kms encrypt \ - --project="${GCLOUD_PROJECT_ID}"\ - --location="global" \ - --keyring="$KEYRING" \ - --key="$KEY" \ - --plaintext-file="${DECRYPTED_FILE}" \ - --ciphertext-file="${DECRYPTED_FILE}${ENC_EXT}" - # Workaround for return. Returns function parameter by reference - eval "$1='${DECRYPTED_FILE}${ENC_EXT}'" -} \ No newline at end of file diff --git a/extension/k8s/demo/secrets.yaml.enc b/extension/k8s/demo/secrets.yaml.enc deleted file mode 100644 index 5fe1f8c0e8a6cc3e9f5a9e2a7edccc2ddb67fd84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 366 zcmV-!0g?U+Bmix$qytYF#aNV~h0UX)<#s>e;tx~Aol$F?&BBijG~$6t^Ag1Z0BD@d z_}Sd4oV(*O%N(XX1Q(VMPSE0n4;N#pu;DYE*%?bK)tVL+wr;-g#M=LurN+Z(h@XLd zp1eZq94I2f5?dZnVJ%HOI{&MCS+>5~p!&#L1qM{6Ge>VWJNXyO<1J$ARd~BJnRWvZ z1WwVm*awVu><>rm3HB5@%t?)C3;Es@ MIU)<5ZQlTpn7GBV>Hq)$ diff --git a/extension/k8s/demo/values.yaml b/extension/k8s/demo/values.yaml deleted file mode 100644 index 5a1d8b2cb..000000000 --- a/extension/k8s/demo/values.yaml +++ /dev/null @@ -1,12 +0,0 @@ -nonSensitiveEnvs: - CTP_PROJECT_KEY: adyen-integration-demo - API_EXTENSION_BASE_URL: https://adyen-payment-demo-extension.ct-app.com - ADYEN_MERCHANT_ACCOUNT: CommercetoolsGmbHDE775 - ADYEN_API_BASE_URL: https://checkout-test.adyen.com/v40 - -ingress: - annotations: - kubernetes.io/ingress.global-static-ip-name: 'ctp-adyen-integration-demo-extension-global-ip' - ingress.gcp.kubernetes.io/pre-shared-cert: 'ct-app' - hosts: - - 'adyen-payment-demo-extension.ct-app.com' \ No newline at end of file diff --git a/extension/k8s/values.yaml b/extension/k8s/values.yaml deleted file mode 100644 index 4ec5f0ac7..000000000 --- a/extension/k8s/values.yaml +++ /dev/null @@ -1,28 +0,0 @@ -fullnameOverride: 'ctp-adyen-integration-service-extension' - -image: - repository: 'eu.gcr.io/professionalserviceslabs/ctp-adyen-integration-extension' - tag: '1.3' - -service: - type: 'NodePort' - -# More on resources: -# https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/resource-qos.md -# https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ -# https://cloud.google.com/compute/docs/machine-types - -ingress: - enabled: true - annotations: - kubernetes.io/ingress.class: 'gce' - kubernetes.io/ingress.allow-http: 'false' - -livenessProbe: - httpGet: - path: '' - - -readinessProbe: - httpGet: - path: '' diff --git a/notification/k8s/crypt/crypt.sh b/notification/k8s/crypt/crypt.sh deleted file mode 100755 index f342fbf74..000000000 --- a/notification/k8s/crypt/crypt.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash -set -e - -declare -a ACTIONS=("encrypt" "decrypt") -declare -a ENVIRONMENTS=("demo") -# Google Cloud project -PROJECT_NAME="ctp-adyen-integration" -GCLOUD_PROJECT_ID="professionalserviceslabs" -SELECTED_APPLICATION="ctp-adyen-integration-notification" - -# Checks if the element exists in the array -# Usage: containsElement "${array[@]}" "blabla" -function containsElement() { - local n=$# - local value=${!n} - for ((i=1;i < $#;i++)) { - if [ "${!i}" == "${value}" ]; then - return 0 - fi - } - return 1 -} - -requireEnvironment(){ - printf "Available environments:\n" - for i in "${!ENVIRONMENTS[@]}" ; do - printf "> %s. %s\n" "$(($i+1))" "${ENVIRONMENTS[$i]}" - done - read -p "Enter the environment number: " SELECTED_ENVIRONMENT_INDEX - printf "\n" - # If the entered environment number is out of `ENVIRONMENTS` then exit - if ! [ "$SELECTED_ENVIRONMENT_INDEX" -ge 1 -a "$SELECTED_ENVIRONMENT_INDEX" -le ${#ENVIRONMENTS[@]} ]; then - printf "Wrong environment number. Exiting with 1.\n" - exit 1 - fi - # Workaround for return. Returns function parameter by reference - eval "$1='${ENVIRONMENTS[$(($SELECTED_ENVIRONMENT_INDEX-1))]}'" -} - -requireAction(){ - printf "Available actions:\n" - for i in "${!ACTIONS[@]}" ; do - printf "> %s. %s\n" "$(($i+1))" "${ACTIONS[$i]}" - done - read -p "Enter the action number: " SELECTED_ACTION_INDEX - printf "\n" - # If the entered action number is out of `ACTIONS` then exit - if ! [ "$SELECTED_ACTION_INDEX" -ge 1 -a "$SELECTED_ACTION_INDEX" -le ${#ACTIONS[@]} ]; then - printf "Wrong action number. Exiting with 1.\n" - exit 1 - fi - # Workaround for return. Returns function parameter by reference - eval "$1='${ACTIONS[$((SELECTED_ACTION_INDEX-1))]}'" -} - -includeScriptOrDie() { - COMMON_SCRIPT="$(dirname "$0")/$1" - if [ ! -r "$COMMON_SCRIPT" ] ; then - echo "Error: script [${COMMON_SCRIPT}] not found!" - exit 1 - fi - . "$COMMON_SCRIPT" -} - -# This function ensures that all necessary arguments are passed to the script. -# If no arguments passed - it asks all of them -# If only 1 argument passed - it asks for other 2 -# and so on. -# It also validates all passed arguments and returns in case of invalid one. -requireArguments() { - local ACTION_VALIDATION_ERROR_MESSAGE="Provided action is invalid." - local ENVIRONMENT_VALIDATION_ERROR_MESSAGE="Provided environment is invalid." - case "$#" in - "0") - requireAction SELECTED_ACTION - requireEnvironment SELECTED_ENVIRONMENT - requestApproval - ;; - "1") - if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@]; then - SELECTED_ACTION=$1; - else return 1 - fi - # requireApplication SELECTED_APPLICATION - requireEnvironment SELECTED_ENVIRONMENT - requestApproval - ;; - *) - if validateInput $1 "${ACTION_VALIDATION_ERROR_MESSAGE}" ACTIONS[@] && \ - # validateInput $2 "${APPLICATION_NAME_VALIDATION_ERROR_MESSAGE}" APPLICATION_NAMES[@] && \ - validateInput $2 "${ENVIRONMENT_VALIDATION_ERROR_MESSAGE}" ENVIRONMENTS[@] ; then - SELECTED_ACTION=$1 - # SELECTED_APPLICATION=$2 - SELECTED_ENVIRONMENT=$2 - else return 1 - fi - ;; - esac -} - -startEncrypt() { - includeScriptOrDie "encrypt.sh" - local ENCRYPTED_FILE='' - encrypt ENCRYPTED_FILE \ - && printf "Encrypted successfully:\n" \ - && ls -l ${ENCRYPTED_FILE} \ - && printf "Don't forget to add/commit the encrypted file\n" -} - -startDecrypt() { - local DECRYPTED_FILE='' - includeScriptOrDie "decrypt.sh" - decrypt DECRYPTED_FILE \ - && printf "\nDecrypted successfully:\n" \ - && ls -l ${DECRYPTED_FILE} -} - -requestApproval() { - while true; do - read -p "Going to execute`echo $'\n> '`${bold}${SELECTED_ACTION} ${SELECTED_APPLICATION} ${SELECTED_ENVIRONMENT} (y/n)${normal} " yn - case ${yn} in - [Yy]* ) echo "Starting to ${SELECTED_ACTION}..."; break;; - [Nn]* ) echo "Terminating process"; exit;; - * ) echo "Please answer yes or no.";; - esac - done -} - -main() { - local bold=$(tput bold) - local normal=$(tput sgr0) - requireArguments $@ || return 1 - - if [ "${SELECTED_ACTION}" = "encrypt" ] ; then - startEncrypt - else - startDecrypt - fi -} - -validateInput() { - if ! containsElement ${!3} "$1"; then - printf "$2\n" - return 1 - fi -} - -if ! main $@; then exit 1; fi diff --git a/notification/k8s/crypt/decrypt.sh b/notification/k8s/crypt/decrypt.sh deleted file mode 100755 index d9ab037c4..000000000 --- a/notification/k8s/crypt/decrypt.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -set -e - -KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" -KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" - -ENC_EXT=".enc" -SECRETS_NAME="secrets.yaml" -DIR="$( cd "$( dirname "$0" )" && pwd )" -DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" -ENCRYPTED_FILE="${DECRYPTED_FILE}${ENC_EXT}" - -decrypt() { - if [ ! -f ${ENCRYPTED_FILE} ]; then - printf "Encrypted secret file not found!\n" - return 1 - fi - - gcloud kms decrypt \ - --project="${GCLOUD_PROJECT_ID}"\ - --location="global" \ - --keyring="$KEYRING" \ - --key="$KEY" \ - --plaintext-file="${DECRYPTED_FILE}" \ - --ciphertext-file="${ENCRYPTED_FILE}" - # Workaround for return. Returns function parameter by reference - eval "$1='${DECRYPTED_FILE}'" -} \ No newline at end of file diff --git a/notification/k8s/crypt/encrypt.sh b/notification/k8s/crypt/encrypt.sh deleted file mode 100644 index 130b803d3..000000000 --- a/notification/k8s/crypt/encrypt.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -set -e - -KEYRING="${PROJECT_NAME}-keyring-${SELECTED_ENVIRONMENT}" -KEY="${SELECTED_APPLICATION}-key-${SELECTED_ENVIRONMENT}" - -ENC_EXT=".enc" -SECRETS_NAME="secrets.yaml" -DIR="$( cd "$( dirname "$0" )" && pwd )" -DECRYPTED_FILE="${DIR}/../${SELECTED_ENVIRONMENT}/${SECRETS_NAME}" - -encrypt() { - if [ ! -f ${DECRYPTED_FILE} ]; then - printf "Secret file not found!\n" - return 1 - fi - - gcloud kms encrypt \ - --project="${GCLOUD_PROJECT_ID}"\ - --location="global" \ - --keyring="$KEYRING" \ - --key="$KEY" \ - --plaintext-file="${DECRYPTED_FILE}" \ - --ciphertext-file="${DECRYPTED_FILE}${ENC_EXT}" - # Workaround for return. Returns function parameter by reference - eval "$1='${DECRYPTED_FILE}${ENC_EXT}'" -} \ No newline at end of file diff --git a/notification/k8s/demo/secrets.yaml.enc b/notification/k8s/demo/secrets.yaml.enc deleted file mode 100644 index 76f255e90849ff34af0d6129ae060d3387d8bf19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 193 zcmV;y06zZ;Bmg-gNb)*AR4hhXL7X5_egB4Y0mPX!(XRMH)f+y /dev/null -fi - -if [ ! -f "$HELM_HOME/helm" ]; then - echo Installing Helm - mkdir -p "$HELM_HOME" - wget -qO- https://storage.googleapis.com/kubernetes-helm/helm-${HELM_VERSION}-linux-amd64.tar.gz | tar zxv -C "$HELM_HOME" - mv "$HELM_HOME/linux-amd64/helm" "$HELM_HOME" - rm -rf "$HELM_HOME/linux-amd64" -fi - -. "$GCLOUD_PATH_APPLY" -gcloud version - -gcloud config set disable_usage_reporting true -gcloud --quiet components update kubectl diff --git a/travis-build/gcloud-login.sh b/travis-build/gcloud-login.sh deleted file mode 100755 index 8077b6586..000000000 --- a/travis-build/gcloud-login.sh +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/bash - -set -e -. "$(dirname "$0")/common.sh" - -echo "Login to gcloud and select project" - -# GCLOUD_KEY expected to be exported as JSON string in Travis settings -# don't forget single quotes around the value (like: -# '{"key":"val"}' -# ) - -# verify mandatory values -verifyMandatoryValues GCLOUD_KEY GCLOUD_PROJECT_ID GCLOUD_ZONE - -# temporary file to store credentials from env variable value, -# because gcloud supports service account logging-in only from file -GCLOUD_CREDENTIALS="$PWD/client-secret.json" -echo "$GCLOUD_KEY" > "${GCLOUD_CREDENTIALS}" - -# Auth, $GCLOUD_KEY must be set in Travis settings -gcloud auth activate-service-account --key-file "${GCLOUD_CREDENTIALS}" -gcloud config set project "$GCLOUD_PROJECT_ID" -gcloud config set compute/zone "$GCLOUD_ZONE" diff --git a/travis-build/gcloud-push-image.sh b/travis-build/gcloud-push-image.sh deleted file mode 100755 index e76464b8a..000000000 --- a/travis-build/gcloud-push-image.sh +++ /dev/null @@ -1,29 +0,0 @@ -#! /bin/bash - -# re-tag "${PROJECT_NAME}:latest" docker image with new registry and commit hash values, -# and push gcloud docker registry. -# this script expects the gcloud SDK is installed and user is logged in. -# See gcloud-login.sh - -set -e -. "$(dirname "$0")/common.sh" - -echo "Gcloud Push Image Script" - -# verify mandatory values -verifyMandatoryValues PROJECT_NAME DOCKER_TAG GCLOUD_PROJECT_ID REGISTRY_NAME - -IMAGE_NAME_LATEST="${PROJECT_NAME}:latest" # local built image name, must already exist -IMAGE_NAME_COMMIT="${PROJECT_NAME}:${DOCKER_TAG}" # image with git tag to push to the registry -FULL_IMAGE_NAME="${REGISTRY_NAME}/${GCLOUD_PROJECT_ID}/${IMAGE_NAME_COMMIT}" - -printf "current gcloud account: [%s]" "$(gcloud config get-value account)" - -# allow docker client push images to gcloud, \ -# "yes" is to allow update local Docker configuration file ~/.docker/config.json -yes | gcloud auth configure-docker - -echo "Pushing new docker image [${FULL_IMAGE_NAME}]" -# Push to Google container registry -docker tag "${IMAGE_NAME_LATEST}" "${FULL_IMAGE_NAME}" -docker push -- "${FULL_IMAGE_NAME}" \ No newline at end of file diff --git a/travis-build/helm-upgrade.sh b/travis-build/helm-upgrade.sh deleted file mode 100755 index 6d709e752..000000000 --- a/travis-build/helm-upgrade.sh +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash - -set -e - -APPLICATION_NAME="$1" -ENVIRONMENT_NAME="$2" -HELM_CHART_TEMPLATE_NAME="$3" -HELM_VALUES_DIR="$4" -IMAGE_TAG="$5" -SCRIPT_DIR="$(dirname "$0")" -CHARTS_DIR="${SCRIPT_DIR}/../../chart-templates/charts" - -printf "\n- Verifying mandatory envs: [APPLICATION_NAME, ENVIRONMENT_NAME, HELM_CHART_TEMPLATE_NAME, HELM_VALUES_DIR, IMAGE_TAG]..\n" -. "${SCRIPT_DIR}/common.sh" -verifyMandatoryValues APPLICATION_NAME ENVIRONMENT_NAME HELM_CHART_TEMPLATE_NAME HELM_VALUES_DIR IMAGE_TAG - -COMMON_INSENSITIVE_ENVS_FILE="$HELM_VALUES_DIR/values.yaml" -ENVIRONMENT_SPECIFIC_INSENSITIVE_ENVS_FILE="$HELM_VALUES_DIR/$ENVIRONMENT_NAME/values.yaml" -SENSITIVE_ENVS_FILE="$HELM_VALUES_DIR/$ENVIRONMENT_NAME/secrets.yaml" - -printf "\n- Upgrading [%s] helm chart template with release name: [%s] on [%s] environment.\n" "$HELM_CHART_TEMPLATE_NAME" "$APPLICATION_NAME" "$ENVIRONMENT_NAME" -helm upgrade --install "$APPLICATION_NAME" --namespace "$ENVIRONMENT_NAME" \ - $(execOptionIfFileExistsAndIsReadable "$COMMON_INSENSITIVE_ENVS_FILE" "-f") \ - $(execOptionIfFileExistsAndIsReadable "$ENVIRONMENT_SPECIFIC_INSENSITIVE_ENVS_FILE" "-f") \ - $(execOptionIfFileExistsAndIsReadable "$SENSITIVE_ENVS_FILE" "-f") \ - $( if [[ -n $IMAGE_TAG ]]; then printf "%s" "--set-string image.tag=${IMAGE_TAG}"; fi ) \ - "$CHARTS_DIR/$HELM_CHART_TEMPLATE_NAME/" diff --git a/travis-build/k8s-charts-clone.sh b/travis-build/k8s-charts-clone.sh deleted file mode 100755 index 0f4614507..000000000 --- a/travis-build/k8s-charts-clone.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/bash - -set -e - -CHARTS_DIR="$1" -SCRIPT_DIR="$(dirname "$0")" - -printf "\n- Verifying mandatory envs: [HELM_CHARTS_REPO, HELM_CHARTS_VERSION, CHARTS_DIR]..\n" -. "${SCRIPT_DIR}/common.sh" -verifyMandatoryValues HELM_CHARTS_REPO HELM_CHARTS_VERSION CHARTS_DIR - -printf "\n- Cloning commercetools/k8s-charts repo..\n" -git clone --branch="$HELM_CHARTS_VERSION" --depth=1 "$HELM_CHARTS_REPO" "$CHARTS_DIR"/ \ No newline at end of file From 3c89fe556031928fe44ad55d198dc21f36e29f11 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Tue, 16 Apr 2019 16:41:02 +0200 Subject: [PATCH 28/30] #43 add script for building docker image --- .travis.yml | 9 ++++++++- travis-build.sh | 18 ++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index f9b5975b0..fabdb127a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,10 +13,17 @@ script: - npm ci - npm run test - if [ "$TEST_DIR" = "extension" ]; then npm run cypress; fi + - cd $TRAVIS_BUILD_DIR + +before_deploy: + - docker login -u="${DOCKER_USERNAME}" -p="${DOCKER_PASSWORD}" + +after_deploy: + - docker logout deploy: - provider: script - script: bash ./travis-build.sh + script: bash ./travis-build.sh "$TEST_DIR" on: tags: true condition: $TRAVIS_TAG =~ ^v[0-9]+.[0-9]+.[0-9]+ \ No newline at end of file diff --git a/travis-build.sh b/travis-build.sh index d8ce07abc..39f1104e3 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -2,16 +2,14 @@ set -e -export REPO_EXT="commercetools/commercetools-adyen-integration-extension" +export REPO=$1 export DOCKER_TAG=`if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then echo "latest"; else echo "wip-${TRAVIS_BRANCH//\//-}" ; fi` -echo "Building Docker image for Extension integration using tag '${REPO_EXT}:${COMMIT}'." -cd ./extension/ -docker build -t "${REPO_EXT}:${COMMIT}" . +echo "Building Docker image using tag 'commercetools/commercetools-adyen-integration-${REPO}:${COMMIT}'." +cd ./$REPO/ +docker build -t "commercetools/commercetools-adyen-integration-${REPO}:${COMMIT}" . -docker login -u="${DOCKER_USERNAME}" -p="${DOCKER_PASSWORD}" -echo "Adding additional tag '${REPO_EXT}:${TRAVIS_TAG}' to already built Docker image '${REPO_EXT}:${COMMIT}'." -docker tag $REPO_EXT:$COMMIT $REPO_EXT:${TRAVIS_TAG}; -echo "Pushing Docker images to repository '${REPO_EXT}' (all local tags are pushed)." -docker push $REPO_EXT -docker logout +echo "Adding additional tag '${REPO}:${TRAVIS_TAG}' to already built Docker image '${REPO}:${COMMIT}'." +docker tag $REPO:$COMMIT $REPO:${TRAVIS_TAG}; +echo "Pushing Docker images to repository '${REPO}' (all local tags are pushed)." +docker push $REPO From 4c139f8401cbeadd442663eb1b397a61b28b0cdc Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Tue, 16 Apr 2019 16:53:54 +0200 Subject: [PATCH 29/30] #43 add script for building docker image --- travis-build.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/travis-build.sh b/travis-build.sh index 39f1104e3..a4d095fc3 100755 --- a/travis-build.sh +++ b/travis-build.sh @@ -2,14 +2,12 @@ set -e -export REPO=$1 -export DOCKER_TAG=`if [ "$TRAVIS_BRANCH" == "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then echo "latest"; else echo "wip-${TRAVIS_BRANCH//\//-}" ; fi` +REPO=$1 +DOCKER_REPOSITORY="commercetools/commercetools-adyen-integration-${REPO}" -echo "Building Docker image using tag 'commercetools/commercetools-adyen-integration-${REPO}:${COMMIT}'." cd ./$REPO/ -docker build -t "commercetools/commercetools-adyen-integration-${REPO}:${COMMIT}" . +echo "Building Docker image using tag '${DOCKER_REPOSITORY}:${TRAVIS_TAG}'." +docker build -t "${DOCKER_REPOSITORY}:${TRAVIS_TAG}" . -echo "Adding additional tag '${REPO}:${TRAVIS_TAG}' to already built Docker image '${REPO}:${COMMIT}'." -docker tag $REPO:$COMMIT $REPO:${TRAVIS_TAG}; -echo "Pushing Docker images to repository '${REPO}' (all local tags are pushed)." -docker push $REPO +echo "Pushing Docker images to repository '${DOCKER_REPOSITORY}'." +docker push "${DOCKER_REPOSITORY}:${TRAVIS_TAG}" From 8cd4dd9c0e707c09d12842f19aeaa6379b3e42f3 Mon Sep 17 00:00:00 2001 From: Lam Tran Date: Tue, 16 Apr 2019 17:17:53 +0200 Subject: [PATCH 30/30] #43 update dockerfile --- extension/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/Dockerfile b/extension/Dockerfile index a4a26baa2..f7fad13ba 100644 --- a/extension/Dockerfile +++ b/extension/Dockerfile @@ -1,4 +1,4 @@ -FROM mhart/alpine-node:10 +FROM mhart/alpine-node:8 MAINTAINER Professional Services WORKDIR /app