#!/usr/bin/env bash

# Requirements
# - Chef workstation
# - Access to chef server
# - Berks plugin
# - git, jsonlint, and other binaries listed below.
# - This script should be called from the base directory of the chef-repo repository

set -ex

KNIFE_BINARY=$(/usr/bin/which knife)
BERKS_BINARY=$(/usr/bin/which berks)
GIT_BINARY=$(/usr/bin/which git)
JSONLINT_BINARY=$(/usr/bin/which jsonlint)
RUBOCOP_BINARY=$(/usr/bin/which rubocop)

set +x

if [ -x ${KNIFE_BINARY} ] && [ -x ${BERKS_BINARY} ] && [ -x ${GIT_BINARY} ] && [ -x ${JSONLINT_BINARY} ] && [ -x ${RUBOCOP_BINARY} ]; then
  printf '%s\n' "Berks, knife, git, jsonlint, and rubocop binaries plugin found. Continuing..."
  printf '%s\n'
else
  printf '%s\n' "Berks, knife, git, jsonlint, or rubocop binaries plugin not found or executable." && exit 1
fi

if [ $# -eq 0 ]; then
  printf '%s\n' "No arguments provided. Will diff latest commit with previous commit."
  START_REVISION=$(git rev-parse HEAD~1)
  END_REVISION=$(git rev-parse HEAD)
else
  START_REVISION=$1
  END_REVISION=$2
fi

printf '%s\n' "Checking revision ${START_REVISION} against ${END_REVISION}"
printf '%s\n'

# Get changed files. Exclude copied, deleted, or renamed files since they no longer exist. Exclude files in repository root.
CHANGED_FILES="$(${GIT_BINARY} diff-tree --no-commit-id --name-only --diff-filter=cdr -r ${START_REVISION} ${END_REVISION} | { grep / || true; })"
printf '%s\n' "Changed files are:" ${CHANGED_FILES}
printf '%s\n'

for file in ${CHANGED_FILES}; do
  if [[ "${file}" == .* ]]; then
      printf '%s\n' "Dotfile detected. Skipping..."
      printf '%s\n'
  else
    # Proceed with all other files
    if [[ "${file}" == *.rb ]]; then
      printf '%s\n' "Ruby file detected. Checking with Rubocop..."
      printf '%s\n'
      if $(${RUBOCOP_BINARY} ${file} | grep -q "no offenses"); then
        printf '%s\n' "Rubocop passed for ${file}."
        printf '%s\n'
      else
        # run actual cmd to show full error message.
        ${RUBOCOP_BINARY} ${file}
        printf '%s\n' "Rubocop detected an error in ${file}." && exit 1
      fi
    elif [[ "${file}" == *.json ]]; then
      printf '%s\n' "JSON file detected. Linting json for ${file}..."
      printf '%s\n'
      if $(${JSONLINT_BINARY} ${file} 2>&1 -q | grep -q "Error"); then
        printf '%s\n' "JSON error in ${file}" && exit 1
      else
        printf '%s\n' "JSON lint passed for ${file}."
        printf '%s\n'
      fi
    elif [[ "${file}" == *.md ]]; then
      printf '%s\n' "Markdown file detected. Moving along..."
      printf '%s\n'
    else
      printf '%s\n' "Unsupported file type detected. Only JSON and Ruby are supported." && exit 1
    fi

    RESOURCE_TYPE=$(printf '%s\n' "${file}" | cut -d '/' -f 1)
    if [[ "${RESOURCE_TYPE}" == "data_bags" ]]; then
      DATA_BAG=$(printf '%s\n' "${file}" | cut -d '/' -f 2)
      UPLOAD_COMMAND="${KNIFE_BINARY} data bag from file ${DATA_BAG} ${file}"
    else
      UPLOAD_COMMAND="${KNIFE_BINARY} ${RESOURCE_TYPE%?} from file ${file}"
    fi
    if ${UPLOAD_COMMAND}; then
      printf '%s\n' "Successfully updated ${file} on ${site}."
      printf '%s\n'
    else
      printf '%s\n' "Error updating ${file} on ${site}." && exit 1
    fi
  fi
done
