diff --git a/xcode/bootstrap/full_code_lint.sh b/xcode/bootstrap/full_code_lint.sh new file mode 100644 index 0000000..a036ef0 --- /dev/null +++ b/xcode/bootstrap/full_code_lint.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +# Description: +# Runs full linting and copy-paste-detection for project +# +# Required environment variables: +# SRCROOT - project directory. +# SCRIPT_DIR - directory of current script. +# +# Optional environment variables: +# See swiftlint.sh and copy_paste_detection.sh for complete list of available variables +# +# Example of usage: +# ./full_code_lint.sh +# + +if [ -z "${SCRIPT_DIR}" ]; then + SCRIPT_DIR=${SRCROOT}/build-scripts/xcode/build_phases +fi + +. ${SRCROOT}/build-scripts/xcode/aux_scripts/install_env.sh swiftlint +FORCE_LINT=true; . ${SCRIPT_DIR}/swiftlint.sh + +. ${SRCROOT}/build-scripts/xcode/aux_scripts/install_env.sh cpd +. ${SCRIPT_DIR}/copy_paste_detection.sh Localization Generated Pods \ No newline at end of file diff --git a/xcode/bootstrap/incremental_code_lint.sh b/xcode/bootstrap/incremental_code_lint.sh new file mode 100644 index 0000000..427a465 --- /dev/null +++ b/xcode/bootstrap/incremental_code_lint.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Description: +# Runs incremental linting for project +# +# Required environment variables: +# SRCROOT - project directory. +# SCRIPT_DIR - directory of current script. +# +# Optional environment variables: +# See swiftlint.sh for complete list of available variables +# +# Example of usage: +# ./incremetal_code_lint.sh +# + +if [ -z "${SCRIPT_DIR}" ]; then + SCRIPT_DIR=${SRCROOT}/build-scripts/xcode/build_phases +fi + +. ${SRCROOT}/build-scripts/xcode/aux_scripts/install_env.sh swiftlint +. ${SCRIPT_DIR}/swiftlint.sh \ No newline at end of file diff --git a/xcode/build_phases/api_generator.sh b/xcode/build_phases/api_generator.sh index ff31f91..0702033 100755 --- a/xcode/build_phases/api_generator.sh +++ b/xcode/build_phases/api_generator.sh @@ -24,36 +24,50 @@ readonly EXIT_SUCCESS=0 readonly EXIT_FAILURE=1 -readonly TRUE=0 -readonly FALSE=1 +readonly TRUE=1 +readonly FALSE=0 readonly LOG_TAG="API-GENERATOR" notice() { - echo "${LOG_TAG}:NOTICE: ${1}" + echo "${LOG_TAG}:NOTICE: ${1}" >&2 } debug() { if [ ! -z "${VERBOSE}" ]; then - echo "${LOG_TAG}:DEBUG: ${1}" + echo "${LOG_TAG}:DEBUG: ${1}" >&2 + fi +} + +exit_on_failure() +{ + eval ${1} + + local -r EXIT_CODE=$? + + if [ ${EXIT_CODE} -ne 0 ]; then + echo "Recent command: \`${1}\` failed with code ${EXIT_CODE}" + + exit ${EXIT_CODE} fi } is_force_run() { if [ -z "${FORCE_RUN}" ]; then - return ${FALSE} + echo ${FALSE} + return fi local -r STR_MODE=`tr "[:upper:]" "[:lower:]" <<< ${FORCE_RUN}` if [ ${STR_MODE} == "yes" ] || [ ${STR_MODE} == "true" ] || [ ${STR_MODE} == "1" ]; then - return ${TRUE} + echo ${TRUE} + else + echo ${FALSE} fi - - return ${FALSE} } is_single_file() @@ -85,6 +99,19 @@ get_api_spec_current_commit() fi } +get_api_spec_status() +{ + if [ -z "${API_SPEC_DIR}" ]; then + if [ ! -z "${1}" ]; then + echo `git -C ${1} status -s` + else + echo `git status -s` + fi + else + echo `git -C ${API_SPEC_DIR} status -s` + fi +} + is_api_spec_under_source_control() { local IS_UNDER_SOURCE_CONTROL_CHECK @@ -99,14 +126,33 @@ is_api_spec_under_source_control() IS_UNDER_SOURCE_CONTROL_CHECK=`git -C ${API_SPEC_DIR} rev-parse --is-inside-work-tree 2>/dev/null` fi - [ ${IS_UNDER_SOURCE_CONTROL_CHECK} = "true" ] + if [ ${IS_UNDER_SOURCE_CONTROL_CHECK} = "true" ]; then + echo ${TRUE} + else + echo ${FALSE} + fi +} + +is_api_spec_has_uncommited_changes() +{ + if [ `is_api_spec_under_source_control` -eq ${TRUE} ]; then + local -r API_SPEC_STATUS=`get_api_spec_status` + + if [ -z "${API_SPEC_STATUS}" ]; then + echo ${FALSE} + else + echo ${TRUE} + fi + else + echo ${FALSE} + fi } is_nothing_changed_since_last_check() { - if is_force_run; then + if [ `is_force_run` -eq ${TRUE} ]; then notice "Force run detected. Skipping commits comparison." - return ${EXIT_FAILURE} + echo ${TRUE} fi if [ -z "${COMMIT_FILE_PATH}" ]; then @@ -114,28 +160,33 @@ is_nothing_changed_since_last_check() local -r COMMIT_FILE_PATH=${1} else debug "COMMIT_FILE_PATH should be defined or passed as first argument!" - return ${EXIT_FAILURE} + echo ${FALSE} fi fi - if is_api_spec_under_source_control; then + if [ `is_api_spec_under_source_control` -eq ${TRUE} ]; then local -r CURRENT_COMMIT=`get_api_spec_current_commit` local -r LAST_CHECKED_COMMIT=`cat ${COMMIT_FILE_PATH} 2> /dev/null || echo ""` if [ ${CURRENT_COMMIT} = "${LAST_CHECKED_COMMIT}" ]; then - return ${EXIT_SUCCESS} + if [ `is_api_spec_has_uncommited_changes` -eq ${TRUE} ]; then + notice "API spec has uncomitted changes." + echo ${FALSE} + else + echo ${TRUE} + fi else - return ${EXIT_FAILURE} + echo ${FALSE} fi else - return ${EXIT_SUCCESS} + echo ${FALSE} fi } record_current_commit() { - if is_force_run; then + if [ `is_force_run` -eq ${TRUE} ]; then notice "Force run detected. Commit won't be recorder." exit ${EXIT_SUCCESS} fi @@ -204,7 +255,9 @@ openapi_codegen() rm -rf ${OUTPUT_PATH}/${API_NAME} # remove previously generated API (if exists) - java -cp "Downloads/${CODEGEN_FILE_NAME}:Downloads/${TINETWORKING_CODEGEN_FILE_NAME}" io.swagger.codegen.v3.cli.SwaggerCodegen generate -l TINetworking -i ${OPEN_API_SPEC_PATH} -o ${OUTPUT_PATH} --additional-properties projectName=${API_NAME} + local -r OPENAPI_COMMAND="java -cp "Downloads/${CODEGEN_FILE_NAME}:Downloads/${TINETWORKING_CODEGEN_FILE_NAME}" io.swagger.codegen.v3.cli.SwaggerCodegen generate -l TINetworking -i ${OPEN_API_SPEC_PATH} -o ${OUTPUT_PATH} --additional-properties projectName=${API_NAME}" + + exit_on_failure "${OPENAPI_COMMAND}" # flatten folders hierarchy @@ -249,7 +302,9 @@ api_generator_codegen() . build-scripts/xcode/aux_scripts/download_file.sh ${FILE_NAME} ${DOWNLOAD_URL} - java -Xmx12g -jar "Downloads/${FILE_NAME}" generate-client-code --output-language SWIFT --specification-path ${API_SPEC_DIR} --output-path ${OUTPUT_PATH} --single-file $(is_single_file) + local -r API_GENERATOR_COMMAND="java -Xmx12g -jar Downloads/${FILE_NAME} generate-client-code --output-language SWIFT --specification-path ${API_SPEC_DIR} --output-path ${OUTPUT_PATH} --single-file $(is_single_file)" + + exit_on_failure "${API_GENERATOR_COMMAND}" } readonly BUILD_PHASES_DIR=${SRCROOT}/build_phases @@ -258,7 +313,7 @@ mkdir -p ${BUILD_PHASES_DIR} readonly COMMIT_FILE_PATH=${BUILD_PHASES_DIR}/api-generator-commit -if is_nothing_changed_since_last_check; then +if [ `is_nothing_changed_since_last_check` -eq ${TRUE} ]; then notice "Nothing was changed. API generation skipped." exit ${EXIT_SUCCESS} fi diff --git a/xcode/build_phases/common/read_input_file_names.sh b/xcode/build_phases/common/read_input_file_names.sh index 7de9439..436445f 100644 --- a/xcode/build_phases/common/read_input_file_names.sh +++ b/xcode/build_phases/common/read_input_file_names.sh @@ -61,13 +61,12 @@ if has_input_files && \ SCRIPT_INPUT_FILE_VARIABLE_NAME="SCRIPT_INPUT_FILE_${i}" SHELL_VARIABLE="\${${SCRIPT_INPUT_FILE_VARIABLE_NAME}}" RESOLVED_FILE_NAME=`envsubst <<< ${SHELL_VARIABLE}` - INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${FILE_NAMES_SEPARATOR}${RESOLVED_FILE_NAME} if [ ! -z ${INPUT_FILE_NAMES} ]; then INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${FILE_NAMES_SEPARATOR} + else + INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${FILE_NAMES_SEPARATOR}${RESOLVED_FILE_NAME} fi - - INPUT_FILE_NAMES=${INPUT_FILE_NAMES}${RESOLVED_FILE_NAME} done elif has_input_file_lists; then for i in `seq 0 $((${SCRIPT_INPUT_FILE_LIST_COUNT}-1))` diff --git a/xcode/build_phases/copy_paste_detection.sh b/xcode/build_phases/copy_paste_detection.sh index 3fe30c1..4b5e71f 100755 --- a/xcode/build_phases/copy_paste_detection.sh +++ b/xcode/build_phases/copy_paste_detection.sh @@ -7,7 +7,7 @@ # $1 $2 $3 $n - folders to exclude from code checking. # # Required environment variables: -# PROJECT_DIR - project directory. +# SRCROOT - project directory. # SCRIPT_DIR - directory of current script. # # Optional environment variables: @@ -15,43 +15,47 @@ # SCRIPT_INPUT_FILE_{N} - file path to directory that should be checked. # # Modified files: -# ${PROJECT_DIR}/code-quality-reports/CPDLog.txt - check report. +# ${SRCROOT}/code-quality-reports/CPDLog.txt - check report. # # Example of usage: -# runner.sh copy_paste_detection.sh Generated Localization Pods +# copy_paste_detection.sh Generated Localization Pods # -readonly EXIT_SUCCESS=0 -readonly EXIT_FAILURE=1 - -. ${SCRIPT_DIR}/../aux_scripts/install_env.sh pmd +EXIT_SUCCESS=0 +EXIT_FAILURE=1 if which pmd >/dev/null; then - readonly REPORTS_DIR="${PROJECT_DIR}/code-quality-reports" + REPORTS_DIR="${SRCROOT}/code-quality-reports" - readonly SOURCES_DIRS=`. ${SCRIPT_DIR}/common/read_input_file_names.sh " " ${PROJECT_DIR}` + SOURCES_DIRS=`. ${SCRIPT_DIR}/common/read_input_file_names.sh " " ${SRCROOT}` - readonly COMMAND_LINE_ARGUMENTS=$@ + COMMAND_LINE_ARGUMENTS=$@ - FOLDERS_TO_EXLUDE="" + FOLDERS_TO_EXCLUDE="" for argument in ${COMMAND_LINE_ARGUMENTS} do - FOLDERS_TO_EXLUDE=${FOLDERS_TO_EXLUDE}"-or -name ${argument} " + FOLDERS_TO_EXCLUDE=${FOLDERS_TO_EXCLUDE}"-or -name ${argument} " done - FOLDERS_TO_EXLUDE=`echo ${FOLDERS_TO_EXLUDE} | cut -c5-` # remove first "-or" + FOLDERS_TO_EXCLUDE=`echo ${FOLDERS_TO_EXCLUDE} | cut -c5-` # remove first "-or" - readonly FILES_TO_EXCLUDE=`find ${PROJECT_DIR} -type d ${FOLDERS_TO_EXLUDE} | paste -sd " " -` + FILES_TO_EXCLUDE=`find ${SRCROOT} -type d ${FOLDERS_TO_EXCLUDE} | paste -sd " " -` mkdir -p ${REPORTS_DIR} - pmd cpd --files ${SOURCES_DIRS} --exclude ${FILES_TO_EXCLUDE} --minimum-tokens 50 --language swift --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer --failOnViolation true > ${REPORTS_DIR}/cpd-output.xml + DIRS_ARGUMENTS="" + + for SOURCE_DIR in ${SOURCES_DIRS}; do + DIRS_ARGUMENTS=${DIRS_ARGUMENTS}" --dir "${SOURCE_DIR} + done + + pmd cpd ${DIRS_ARGUMENTS} --exclude ${FILES_TO_EXCLUDE} --minimum-tokens 50 --language swift --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer --skip-lexical-errors true > ${REPORTS_DIR}/cpd-output.xml php ${SCRIPT_DIR}/../aux_scripts/cpd_script.php ${REPORTS_DIR}/cpd-output.xml | tee ${REPORTS_DIR}/CPDLog.txt - # Make paths relative to PROJECT_DIR, so different developers won't rewrite entire file - readonly SED_REPLACEMENT_STRING=$(echo ${PROJECT_DIR} | sed "s/\//\\\\\//g") + # Make paths relative to SRCROOT, so different developers won't rewrite entire file + SED_REPLACEMENT_STRING=$(echo ${SRCROOT} | sed "s/\//\\\\\//g") sed -i '' "s/${SED_REPLACEMENT_STRING}//g" "${REPORTS_DIR}/CPDLog.txt" else diff --git a/xcode/build_phases/swiftlint.sh b/xcode/build_phases/swiftlint.sh index 966dec9..916f8b0 100755 --- a/xcode/build_phases/swiftlint.sh +++ b/xcode/build_phases/swiftlint.sh @@ -32,8 +32,10 @@ readonly SOURCES_DIRS=`. ${SCRIPT_DIR}/common/read_input_file_names.sh "\n" ${SR if [ -z "${SWIFTLINT_EXECUTABLE}" ]; then if [ ! -z "${1}" ]; then readonly SWIFTLINT_EXECUTABLE=${1} - else + elif [ ! -z "${PODS_ROOT}" ]; readonly SWIFTLINT_EXECUTABLE=${PODS_ROOT}/SwiftLint/swiftlint + else + readonly SWIFTLINT_EXECUTABLE=${SRCROOT}/Pods/SwiftLint/swiftlint fi fi