From 79e7728f529e052139b26033b9c942e319f77da1 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Tue, 17 Oct 2023 16:59:47 +0300 Subject: [PATCH 01/25] DF-2333: add commands to delete local & remote branches in repo before creating new one --- check_data_and_create_pr.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 95e53f5..cae9ec1 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -9,6 +9,13 @@ mv temp/* . mv temp//.git* . rmdir temp + +# remove unused branches before creating new +git checkout master +# delete merged and unmerged remote branches +git branch --merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; +git branch --no-merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; + # create a new branch for update git checkout master PR_BRANCH_NAME="update_$(git log -n 1 --pretty=format:%H)" From a09d9c28bd3fcfe7f491e565d12ec49e031d2cfb Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Wed, 18 Oct 2023 17:09:15 +0300 Subject: [PATCH 02/25] DF-2333: debug script on GH runner done --- check_data_and_create_pr.sh | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index cae9ec1..a27a2f3 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -1,5 +1,8 @@ #!/bin/bash + +# setted by GitHub set -e +set +o pipefail bash scripts/validate_token.sh @@ -9,13 +12,25 @@ mv temp/* . mv temp//.git* . rmdir temp - +set +e +set +o pipefail # remove unused branches before creating new git checkout master -# delete merged and unmerged remote branches -git branch --merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; -git branch --no-merged | egrep -v "(^\*|master)" | xargs -I % sh -c 'git branch -D %; git push --delete origin %'; +git branch --list | cat +merged_branches=$(git branch -r --merged | grep "update_*" -c) +nomerged_branches=$(git branch --no-merged | grep "update_*" -c) +total_branches=$(($merged_branches+$nomerged_branches)) + +# delete all merged and unmerged remote `update_*` branches +if [[ $total_branches > 0 ]] +then + git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin + git branch --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; +else + echo "No temporary branch to remove" +fi +set -e # create a new branch for update git checkout master PR_BRANCH_NAME="update_$(git log -n 1 --pretty=format:%H)" @@ -30,5 +45,6 @@ python3 scripts/simple_data_check.py bash scripts/close_pr_if_exists.sh # create new PR +set +e export GH_TOKEN=${ACTION_TOKEN} gh api -X POST /repos/tradingview-pine-seeds/${REPO_NAME}/pulls -f base="master" -f head="${REPO_OWNER}:${PR_BRANCH_NAME}" -f title="Upload data" > /dev/null 2>&1 From 8362b2667e686c875fd114ef3792e0de8a3d572b Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 26 Oct 2023 17:23:43 +0300 Subject: [PATCH 03/25] DF-2333: add extra command for 0 result code --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index a27a2f3..1f88702 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -48,3 +48,4 @@ bash scripts/close_pr_if_exists.sh set +e export GH_TOKEN=${ACTION_TOKEN} gh api -X POST /repos/tradingview-pine-seeds/${REPO_NAME}/pulls -f base="master" -f head="${REPO_OWNER}:${PR_BRANCH_NAME}" -f title="Upload data" > /dev/null 2>&1 +echo From 79c74b704760f4ea9e0a6d48564bcd5209f7997f Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Wed, 18 Oct 2023 09:11:48 +0300 Subject: [PATCH 04/25] DF-2335: more clear validation errors --- simple_data_check.py | 68 ++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index 6859995..b18014d 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -4,7 +4,7 @@ the specification: https://github.com/tradingview-pine-seeds/pine-seeds-docs/blob/main/data.md """ - +from __future__ import annotations import glob import json import os @@ -12,18 +12,19 @@ from os.path import exists, isfile from sys import exit as sys_exit, argv from datetime import datetime -from re import compile as re_compile +from re import Pattern, compile as re_compile +from typing import Any, Dict, List, Tuple -TODAY = datetime.now().strftime("%Y%m%dT") -FLOAT_RE = re_compile(r'^[+-]?([0-9]*[.])?[0-9]+$') -SYMBOL_RE = re_compile(r'^[_.0-9A-Z]+$') -DESCRIPTION_RE = re_compile(r'^.+$') -PRICESCALE_RE = re_compile(r'^1(0){0,22}$') -REPORTS_PATH = argv[1] if len(argv) > 1 else None +TODAY: str = datetime.now().strftime("%Y%m%dT") +FLOAT_RE: Pattern[str] = re_compile(r'^[+-]?([0-9]*[.])?[0-9]+$') +SYMBOL_RE: Pattern[str] = re_compile(r'^[_.0-9A-Z]+$') +DESCRIPTION_RE: Pattern[str] = re_compile(r'^.+$') +PRICESCALE_RE: Pattern[str] = re_compile(r'^1(0){0,22}$') +REPORTS_PATH: str = argv[1] if len(argv) > 1 else None -def check_type(values, val_type): +def check_type(values: Any, val_type: type) -> bool: """ check that values is list of types or single type value """ if isinstance(values, list): for val in values: @@ -34,7 +35,7 @@ def check_type(values, val_type): return isinstance(values, val_type) -def check_length(values: any, max_length: int): +def check_length(values: Any, max_length: int) -> bool: """ check length of each element in values. Return True only when all elements have length less or equal to max_length.""" if isinstance(values, list): for val in values: @@ -45,7 +46,7 @@ def check_length(values: any, max_length: int): return True -def check_regexp(values, regexp): +def check_regexp(values: Any, regexp: Pattern[str]) -> bool: """ check that str() of each element in values match to provided regexp """ if isinstance(values, list): for val in values: @@ -56,7 +57,7 @@ def check_regexp(values, regexp): return True -def check_field_data(name, values, val_type, regexp, max_length, quantity, sym_file): +def check_field_data(name: str, values: Any, val_type: type, regexp: Pattern[str], max_length: int, quantity: int, sym_file: str) -> List[str]: """ check the field data according type, max_length and quantity of elements """ errors = [] if not check_type(values, val_type): @@ -78,7 +79,7 @@ def check_field_data(name, values, val_type, regexp, max_length, quantity, sym_f return errors -def get_duplicates(items: list): +def get_duplicates(items: List[Any]) -> set: """ Returns the set of duplicated items in list """ existing = set() dup = set() @@ -90,11 +91,11 @@ def get_duplicates(items: list): return dup -def check_symbol_info(sym_file): +def check_symbol_info(sym_file: str) -> Tuple[List[str], List[str]]: """ check symbol file """ - errors = [] + errors: List[str] = [] with open(sym_file) as file: - sym_data = json.load(file) + sym_data: Dict[str, Any] = json.load(file) expected_fields = set(("symbol", "description", "pricescale")) exists_fields = set(sym_data.keys()) if exists_fields != expected_fields: @@ -103,7 +104,7 @@ def check_symbol_info(sym_file): else: errors.append(F"The {sym_file} file doesn't have required fields: {', '.join(i for i in expected_fields.difference(exists_fields))}") return [], errors - symbols = sym_data["symbol"] + symbols: List[str] = sym_data["symbol"] errors = check_field_data("symbol", symbols, str, SYMBOL_RE, 42, 0, sym_file) if len(set(symbols)) != len(symbols): errors.append(F"The {sym_file} file contain duplicated symbols: {', '.join(get_duplicates(symbols))}. All symbols must have unique names.") @@ -120,10 +121,10 @@ def check_symbol_info(sym_file): return symbols, errors -def check_data_line(data_line, file_path, i): +def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], str]: """ check values of data file's line """ - messages = [] - date = None + messages: List[str] = [] + date: str = None if data_line.startswith("#"): messages.append(F'{file_path} has comment in line {i}') return messages, date @@ -136,18 +137,27 @@ def check_data_line(data_line, file_path, i): if len(vals) != 6: # YYYYMMDDT, o, h, l, c, v messages.append(F'{file_path}:{i} contains incorrect number of elements (expected: 6, actual: {len(vals)})') return messages, date + + check_ok = True + # validate float try: for val in (vals[i] for i in range(1, 6)): if FLOAT_RE.match(val) is None: raise ValueError + open_price, high_price, low_price, close_price = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]) + except ValueError: + check_ok = False + messages.append(F'{file_path}:{i} float values validation error. The float value can\'t be NAN/+INF/-INF') + # validate date + try: if len(vals[0]) != 9: # value '202291T' is considered as correct date 2022/09/01 by datetime.strptime but specification require zero-padded values raise ValueError - open_price, high_price, low_price, close_price = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]) _, volume = datetime.strptime(vals[0], '%Y%m%dT'), float(vals[5]) except (ValueError, TypeError): - messages.append(F'{file_path}:{i} contains invalid value types. ' + - 'Types must be: string(YYYYMMDDT), float, float, float, float, float. The float value can\'t be NAN/+INF/-INF') - else: + check_ok = False + messages.append(F'{file_path}:{i} date validation error, date format have to be YYYYMMDDT, for example: 20230101T') + + if check_ok: date = vals[0] if not (open_price <= high_price >= close_price >= low_price <= open_price and high_price >= low_price): messages.append(F'{file_path}:{i} contains invalid OHLC values. Values must comply with the rules: h >= o, h >= l, h >= c, l <= o, l <= c).') @@ -160,7 +170,7 @@ def check_data_line(data_line, file_path, i): return messages, date -def check_datafile(file_path, problems): +def check_datafile(file_path: str, problems: Dict[str, List[Any]]) -> None: """ Check data file """ dates = set() last_date = "" @@ -180,7 +190,7 @@ def check_datafile(file_path, problems): last_date = date dates.add(date) -def check_data_files(sym_file_path, symbols, problems): +def check_data_files(sym_file_path: str, symbols: List[str], problems: Dict[str, List[Any]]) -> None: """ check all files into data/ folder """ sym_set = set(symbols) for file in glob.glob("data/*"): @@ -200,7 +210,7 @@ def check_data_files(sym_file_path, symbols, problems): problems["missed_files"].append(symbol) -def fail(msg): +def fail(msg: str) -> None: """ report about fail and exit with non-zero exit code""" if REPORTS_PATH is None: print(msg) @@ -210,7 +220,7 @@ def fail(msg): sys_exit(0) -def main(): +def main() -> None: """ main routine """ group = getenv("GROUP") if group == "": @@ -224,6 +234,7 @@ def main(): problems["errors"] = sym_errors if len(symbols) > 0: check_data_files(sym_file_path, symbols, problems) + # report warnings if len(problems["missed_files"]) > 0: warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' @@ -232,6 +243,7 @@ def main(): else: with open(os.path.join(REPORTS_PATH, "warnings.txt"), "a") as file: file.write(warning) + # report errors if len(problems["errors"]) > 0: problems_list = "\n ".join(problems["errors"]) From 589d09130085018236f1d861492bb2e3e2919fe5 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Fri, 20 Oct 2023 17:52:21 +0300 Subject: [PATCH 05/25] DF-2335: fix bug in float validation --- simple_data_check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index b18014d..1d3bfa4 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -144,7 +144,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], for val in (vals[i] for i in range(1, 6)): if FLOAT_RE.match(val) is None: raise ValueError - open_price, high_price, low_price, close_price = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]) + open_price, high_price, low_price, close_price, volume = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]), float(vals[5]) except ValueError: check_ok = False messages.append(F'{file_path}:{i} float values validation error. The float value can\'t be NAN/+INF/-INF') @@ -152,7 +152,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], try: if len(vals[0]) != 9: # value '202291T' is considered as correct date 2022/09/01 by datetime.strptime but specification require zero-padded values raise ValueError - _, volume = datetime.strptime(vals[0], '%Y%m%dT'), float(vals[5]) + _ = datetime.strptime(vals[0], '%Y%m%dT') except (ValueError, TypeError): check_ok = False messages.append(F'{file_path}:{i} date validation error, date format have to be YYYYMMDDT, for example: 20230101T') From 587eb364f342aa6b8920ac3177a142b255108ed1 Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <147723152+dpoliakov-tv@users.noreply.github.com> Date: Fri, 27 Oct 2023 18:37:46 +0300 Subject: [PATCH 06/25] DF-2472: add check git diff changed files fo GH PR limit (#7) * DF-2472: add check git diff changed files fo GH PR limit --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 1f88702..327d0c7 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -31,6 +31,7 @@ else fi set -e + # create a new branch for update git checkout master PR_BRANCH_NAME="update_$(git log -n 1 --pretty=format:%H)" From fbc336873deb06dac83a5cd5fd322eeed1d7dabe Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <147723152+dpoliakov-tv@users.noreply.github.com> Date: Sat, 28 Oct 2023 11:37:55 +0300 Subject: [PATCH 07/25] hotfix: changes compare operator in if statement (#8) --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 327d0c7..ffdd18b 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -28,6 +28,7 @@ then git branch --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; else echo "No temporary branch to remove" + fi set -e From 07b157c75e2dc333f7c059d630e42e075e79d326 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 2 Nov 2023 18:01:38 +0300 Subject: [PATCH 08/25] DF-2455: compress messages to report and warnings files --- simple_data_check.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/simple_data_check.py b/simple_data_check.py index 1d3bfa4..59beb48 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -8,7 +8,6 @@ import glob import json import os -from os import getenv from os.path import exists, isfile from sys import exit as sys_exit, argv from datetime import datetime @@ -22,6 +21,8 @@ DESCRIPTION_RE: Pattern[str] = re_compile(r'^.+$') PRICESCALE_RE: Pattern[str] = re_compile(r'^1(0){0,22}$') REPORTS_PATH: str = argv[1] if len(argv) > 1 else None +MAX_ERRORS_IN_MSG: int = int(os.getenv("MAX_ERRORS_IN_MSG", 50)) # max show errors in console, file or PR message +THRESHOLD_ERR: int = int(os.getenv('THRESHOLD_ERR', 10)) def check_type(values: Any, val_type: type) -> bool: @@ -234,10 +235,15 @@ def main() -> None: problems["errors"] = sym_errors if len(symbols) > 0: check_data_files(sym_file_path, symbols, problems) - + # report warnings - if len(problems["missed_files"]) > 0: - warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' + len_problems_missed_files = len(problems["missed_files"]) + if len_problems_missed_files > 0: + if len_problems_missed_files > MAX_ERRORS_IN_MSG + THRESHOLD_ERR: + warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"][:MAX_ERRORS_IN_MSG])} and {len_problems_missed_files - MAX_ERRORS_IN_MSG} other CSV files.\n' + else: + warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' + if REPORTS_PATH is None: print(warning) else: @@ -245,9 +251,16 @@ def main() -> None: file.write(warning) # report errors - if len(problems["errors"]) > 0: - problems_list = "\n ".join(problems["errors"]) - fail(F'ERROR: the following issues were found in the repository files:\n {problems_list}\n') + len_problems_errors = len(problems["errors"]) + if len_problems_errors > 0: + if len_problems_errors > MAX_ERRORS_IN_MSG + THRESHOLD_ERR: + problems_list = "\n ".join(problems["errors"][:MAX_ERRORS_IN_MSG]) + error_msg = F'ERROR: the following issues were found in the repository files:\n {problems_list} and {len_problems_errors - MAX_ERRORS_IN_MSG} other errors. \n' + else: + problems_list = "\n ".join(problems["errors"]) + error_msg = F'ERROR: the following issues were found in the repository files:\n {problems_list}\n' + + fail(error_msg) if __name__ == "__main__": From dc2acaca671ce7590554452bea093466a8f6b55f Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Fri, 3 Nov 2023 11:18:43 +0300 Subject: [PATCH 09/25] DF-2455: import fix --- simple_data_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple_data_check.py b/simple_data_check.py index 59beb48..14e3c88 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -223,7 +223,7 @@ def fail(msg: str) -> None: def main() -> None: """ main routine """ - group = getenv("GROUP") + group = os.getenv("GROUP") if group == "": fail("ERROR: the GROUP environment variable is not set") sym_file_path = F"symbol_info/{group}.json" From 11af4f82973230abcf6eeeacfc37fc5bf4efeaf9 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 9 Nov 2023 15:44:49 +0300 Subject: [PATCH 10/25] fix counting and removing remote no-merged branches --- check_data_and_create_pr.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index ffdd18b..4aa1f3a 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -18,14 +18,14 @@ set +o pipefail git checkout master git branch --list | cat merged_branches=$(git branch -r --merged | grep "update_*" -c) -nomerged_branches=$(git branch --no-merged | grep "update_*" -c) +nomerged_branches=$(git branch -r --no-merged | grep "update_*" -c) total_branches=$(($merged_branches+$nomerged_branches)) # delete all merged and unmerged remote `update_*` branches if [[ $total_branches > 0 ]] then git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin - git branch --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; + git branch -r --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; else echo "No temporary branch to remove" From 95bc0c31523841824566deb7eceb9e90a1969af6 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 9 Nov 2023 15:52:42 +0300 Subject: [PATCH 11/25] delete only remote branches --- check_data_and_create_pr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 4aa1f3a..d11f100 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -25,7 +25,7 @@ total_branches=$(($merged_branches+$nomerged_branches)) if [[ $total_branches > 0 ]] then git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin - git branch -r --no-merged | grep "update_*" | xargs -I % bash -c 'git branch -D %; git push --delete origin %'; + git branch -r --no-merged | grep "update_*" | cut -d "/" -f 2| xargs git push --delete origin else echo "No temporary branch to remove" From 2a5cae2e0ad99074dda4e8f72be3243485ee36a9 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Wed, 29 Nov 2023 18:32:03 +0300 Subject: [PATCH 12/25] DF-2546: colorized outpu --- check_data_and_create_pr.sh | 22 +++++++++++++++++----- close_pr_if_exists.sh | 8 ++++---- simple_data_check.py | 8 +++++--- validate_token.sh | 12 ++++++------ 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index d11f100..d32f062 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -4,7 +4,22 @@ set -e set +o pipefail -bash scripts/validate_token.sh +export TERM=xterm-color +GRN="\033[1;92m" # success messages, green +RED="\033[1;91m" # error messages, red +BL="\033[1;94m" # info messages (usually skip messages), blue +YEL="\033[1;93m" # warnings, yellow +MGN='\033[1;95m' # start step info, magenta +CYA='\033[1;96m' # more bright info messages, cyan +ENDC="\033[0m" # end of color message + +color_message() { + message=$1 + color=$2 + echo -e "${color}${message}${ENDC}" +} + +. scripts/validate_token.sh # checkout fork repo (via temp dir as current dir is not emply and it does't allow to check out repo in it) git clone "https://${REPO_OWNER}:${ACTION_TOKEN}@github.com/${REPO_OWNER}/${REPO_NAME}.git" temp @@ -26,9 +41,6 @@ if [[ $total_branches > 0 ]] then git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin git branch -r --no-merged | grep "update_*" | cut -d "/" -f 2| xargs git push --delete origin -else - echo "No temporary branch to remove" - fi set -e @@ -44,7 +56,7 @@ export GROUP=${REPO_NAME} python3 scripts/simple_data_check.py # close previous PR if it exists -bash scripts/close_pr_if_exists.sh +. scripts/close_pr_if_exists.sh # create new PR set +e diff --git a/close_pr_if_exists.sh b/close_pr_if_exists.sh index 3912118..5a5a7cf 100755 --- a/close_pr_if_exists.sh +++ b/close_pr_if_exists.sh @@ -3,7 +3,7 @@ echo "${ACTION_TOKEN}" | gh auth login --with-token > /dev/null 2>&1 if [ -z $? ] then - echo "Authorization failed. Update ACTION_TOKEN in the repository secrets." + echo $(color_message "Authorization failed. Update ACTION_TOKEN in the repository secrets." $RED) exit 1 fi @@ -11,18 +11,18 @@ EXISTING_PRS=$(gh api -X GET /repos/tradingview-pine-seeds/"$REPO_NAME"/pulls) if [ "$EXISTING_PRS" != "[]" ]; then NUMBER_OF_PRS=$(echo "$EXISTING_PRS" | jq length) if [ "$NUMBER_OF_PRS" != 1 ]; then - echo "There is more than one PR open. To resolve the issue, contact pine.seeds@tradingview.com with the Pine Seeds Issue subject." + echo $(color_message "There is more than one PR open. To resolve the issue, contact pine.seeds@tradingview.com with the Pine Seeds Issue subject." $RED) exit 1 fi BASE_LABEL=$(echo "$EXISTING_PRS" | jq -r ".[0].base.label") if [ "$BASE_LABEL" != "tradingview-pine-seeds:master" ]; then - echo "base = $BASE_LABEL is incorrect" + echo $(color_message "base = $BASE_LABEL is incorrect" $RED) exit 1 fi HEAD_LABEL=$(echo "$EXISTING_PRS" | jq -r ".[0].head.label") OWNER="${HEAD_LABEL%:*}" if [ "${OWNER}" != "$REPO_OWNER" ]; then - echo "head = $HEAD_LABEL is incorrect" + echo $(color_message "head = $HEAD_LABEL is incorrect" $RED) exit 1 fi NUM=$(echo "$EXISTING_PRS" | jq -r ".[0].number") diff --git a/simple_data_check.py b/simple_data_check.py index d12bdc7..e293684 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -23,7 +23,9 @@ REPORTS_PATH: str = argv[1] if len(argv) > 1 else None MAX_ERRORS_IN_MSG: int = int(os.getenv("MAX_ERRORS_IN_MSG", 50)) # max show errors in console, file or PR message THRESHOLD_ERR: int = int(os.getenv('THRESHOLD_ERR', 10)) - +RED="\033[1;91m" # error messages, red +YEL="\033[1;93m" # warnings, yellow +ENDC="\033[0m" # end of color message def check_type(values: Any, val_type: type) -> bool: @@ -215,7 +217,7 @@ def check_data_files(sym_file_path: str, symbols: List[str], problems: Dict[str, def fail(msg: str) -> None: """ report about fail and exit with non-zero exit code""" if REPORTS_PATH is None: - print(msg) + print(RED+msg+ENDC) sys_exit(1) with open(os.path.join(REPORTS_PATH, "report.txt"), "a") as file: file.write(msg) @@ -246,7 +248,7 @@ def main() -> None: warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' if REPORTS_PATH is None: - print(warning) + print(YEL+warning+ENDC) else: with open(os.path.join(REPORTS_PATH, "warnings.txt"), "a") as file: file.write(warning) diff --git a/validate_token.sh b/validate_token.sh index 7bdcfa7..088af30 100755 --- a/validate_token.sh +++ b/validate_token.sh @@ -1,32 +1,32 @@ if [ -z "${ACTION_TOKEN}" ] then - echo "Failed to find ACTION_TOKEN. Make sure that ACTION_TOKEN is set in the repository secrets." + echo $(color_message "Failed to find ACTION_TOKEN. Make sure that ACTION_TOKEN is set in the repository secrets." $RED) exit 1 fi RESP=$(echo "${ACTION_TOKEN}" | gh auth login --with-token 2>&1) if [ $? -ne 0 ] then - echo "Authorization failed. Make sure that your ACTION_TOKEN is valid and not expired." + echo $(color_message "Authorization failed. Make sure that your ACTION_TOKEN is valid and not expired." $RED) exit 1 fi if [[ "$RESP" == *"error"* ]]; then - echo "Insufficient scope error. Provide ACTION_TOKEN with the repo, workflow, and admin:org scopes." + echo $(color_message "Insufficient scope error. Provide ACTION_TOKEN with the repo, workflow, and admin:org scopes." $RED) exit 1 fi SCOPES=$(gh auth status 2>&1 | grep "scopes") valid=true if [[ "$SCOPES" != *"workflow"* ]]; then - echo "Insufficient scope error. Provide ACTION_TOKEN with the workflow scope." + echo echo $(color_message "Insufficient scope error. Provide ACTION_TOKEN with the workflow scope." $RED) valid=false fi if [[ "$SCOPES" != *"admin:org"* ]]; then - echo "Insufficient scope error. Provide ACTION_TOKEN with the admin:org scope." + echo $(color_message "Insufficient scope error. Provide ACTION_TOKEN with the admin:org scope." $RED) valid=false fi @@ -34,4 +34,4 @@ if ! $valid ; then exit 1 fi -echo "ACTION_TOKEN validation successful" +echo $(color_message "ACTION_TOKEN validation successful" $GRN) From 145b8625085302375515ad09e289890021a4cd90 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Mon, 18 Dec 2023 11:37:38 +0300 Subject: [PATCH 13/25] debug --- check_data_and_create_pr.sh | 2 +- close_pr_if_exists.sh | 2 ++ validate_token.sh | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index d32f062..ae81a57 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -1,7 +1,7 @@ #!/bin/bash # setted by GitHub -set -e +set -ex set +o pipefail export TERM=xterm-color diff --git a/close_pr_if_exists.sh b/close_pr_if_exists.sh index 5a5a7cf..bcc120b 100755 --- a/close_pr_if_exists.sh +++ b/close_pr_if_exists.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -x + echo "${ACTION_TOKEN}" | gh auth login --with-token > /dev/null 2>&1 if [ -z $? ] then diff --git a/validate_token.sh b/validate_token.sh index 088af30..c2faaac 100755 --- a/validate_token.sh +++ b/validate_token.sh @@ -1,3 +1,6 @@ +#!/bin/bash + +set -x if [ -z "${ACTION_TOKEN}" ] then From 0b22ae9cec13b00ef7bc893d9323a545397eab1b Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Mon, 18 Dec 2023 11:46:04 +0300 Subject: [PATCH 14/25] debug --- validate_token.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/validate_token.sh b/validate_token.sh index c2faaac..f573e90 100755 --- a/validate_token.sh +++ b/validate_token.sh @@ -18,6 +18,7 @@ fi if [[ "$RESP" == *"error"* ]]; then echo $(color_message "Insufficient scope error. Provide ACTION_TOKEN with the repo, workflow, and admin:org scopes." $RED) + echo "Insufficient scope error. Provide ACTION_TOKEN with the repo, workflow, and admin:org scopes." exit 1 fi From b3ad30e145634747e33b34f26e303f7e7c4bf121 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Mon, 18 Dec 2023 11:47:45 +0300 Subject: [PATCH 15/25] fix: set -e in main script --- check_data_and_create_pr.sh | 2 +- close_pr_if_exists.sh | 2 -- validate_token.sh | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index ae81a57..d3b7ed5 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -1,7 +1,6 @@ #!/bin/bash # setted by GitHub -set -ex set +o pipefail export TERM=xterm-color @@ -21,6 +20,7 @@ color_message() { . scripts/validate_token.sh +set -e # checkout fork repo (via temp dir as current dir is not emply and it does't allow to check out repo in it) git clone "https://${REPO_OWNER}:${ACTION_TOKEN}@github.com/${REPO_OWNER}/${REPO_NAME}.git" temp mv temp/* . diff --git a/close_pr_if_exists.sh b/close_pr_if_exists.sh index bcc120b..5a5a7cf 100755 --- a/close_pr_if_exists.sh +++ b/close_pr_if_exists.sh @@ -1,7 +1,5 @@ #!/bin/bash -set -x - echo "${ACTION_TOKEN}" | gh auth login --with-token > /dev/null 2>&1 if [ -z $? ] then diff --git a/validate_token.sh b/validate_token.sh index f573e90..6da75a6 100755 --- a/validate_token.sh +++ b/validate_token.sh @@ -1,7 +1,5 @@ #!/bin/bash -set -x - if [ -z "${ACTION_TOKEN}" ] then echo $(color_message "Failed to find ACTION_TOKEN. Make sure that ACTION_TOKEN is set in the repository secrets." $RED) @@ -18,7 +16,6 @@ fi if [[ "$RESP" == *"error"* ]]; then echo $(color_message "Insufficient scope error. Provide ACTION_TOKEN with the repo, workflow, and admin:org scopes." $RED) - echo "Insufficient scope error. Provide ACTION_TOKEN with the repo, workflow, and admin:org scopes." exit 1 fi From 347dd1249e9f27c2c50e0f2a159ab9651d8dae21 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Tue, 19 Dec 2023 17:25:11 +0300 Subject: [PATCH 16/25] DF-2449: add checking exist data folder and count its contests --- check_data_and_create_pr.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index d3b7ed5..3c7394c 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -27,6 +27,14 @@ mv temp/* . mv temp//.git* . rmdir temp +if [ ! -d "data" ]; then + echo $(color_message "'data' directory is empty or not exist" $RED) + exit 1 +elif [[ $(ls "data" | wc -l) -eq 0 ]]; then + echo $(color_message "'data' directory is empty or not exist" $RED) + exit 1 +fi + set +e set +o pipefail # remove unused branches before creating new From b9c9666e759cb7f49c649af3d7155a85f3b7b981 Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <147723152+dpoliakov-tv@users.noreply.github.com> Date: Wed, 20 Dec 2023 18:26:26 +0300 Subject: [PATCH 17/25] Update check_data_and_create_pr.sh --- check_data_and_create_pr.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 3c7394c..ad1b2c0 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -28,10 +28,10 @@ mv temp//.git* . rmdir temp if [ ! -d "data" ]; then - echo $(color_message "'data' directory is empty or not exist" $RED) + echo $(color_message "ERROR: /`data/` directory is empty or not exist" $RED) exit 1 elif [[ $(ls "data" | wc -l) -eq 0 ]]; then - echo $(color_message "'data' directory is empty or not exist" $RED) + echo $(color_message "ERROR: /`data/` directory is empty or not exist" $RED) exit 1 fi From a5b70cf9a2c44970c01b72ee09e617e40d926f01 Mon Sep 17 00:00:00 2001 From: Dmitry Polyakov <147723152+dpoliakov-tv@users.noreply.github.com> Date: Wed, 20 Dec 2023 18:27:33 +0300 Subject: [PATCH 18/25] Update check_data_and_create_pr.sh --- check_data_and_create_pr.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index ad1b2c0..160547a 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -28,10 +28,10 @@ mv temp//.git* . rmdir temp if [ ! -d "data" ]; then - echo $(color_message "ERROR: /`data/` directory is empty or not exist" $RED) + echo $(color_message "ERROR: 'data' directory is empty or not exist" $RED) exit 1 elif [[ $(ls "data" | wc -l) -eq 0 ]]; then - echo $(color_message "ERROR: /`data/` directory is empty or not exist" $RED) + echo $(color_message "ERROR: 'data' directory is empty or not exist" $RED) exit 1 fi From ffa1eaca1d60dc615dc828f584d18b77a85a7fa5 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Wed, 29 Nov 2023 18:32:03 +0300 Subject: [PATCH 19/25] DF-2546: colorized output & correct set -e in main script --- check_data_and_create_pr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 160547a..7c33f18 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -70,4 +70,4 @@ python3 scripts/simple_data_check.py set +e export GH_TOKEN=${ACTION_TOKEN} gh api -X POST /repos/tradingview-pine-seeds/${REPO_NAME}/pulls -f base="master" -f head="${REPO_OWNER}:${PR_BRANCH_NAME}" -f title="Upload data" > /dev/null 2>&1 -echo +echo From 36395ead5eec78af1e4b9a4210c9f763077b8672 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 21 Dec 2023 11:52:57 +0300 Subject: [PATCH 20/25] DF-2449: upd logic for gitkeep --- check_data_and_create_pr.sh | 4 ++-- simple_data_check.py | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 7c33f18..9d42380 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -28,10 +28,10 @@ mv temp//.git* . rmdir temp if [ ! -d "data" ]; then - echo $(color_message "ERROR: 'data' directory is empty or not exist" $RED) + echo $(color_message "ERROR: 'data' directory is empty or not exist for. Please add '.gitkeep' file in 'data' folder if need" $RED) exit 1 elif [[ $(ls "data" | wc -l) -eq 0 ]]; then - echo $(color_message "ERROR: 'data' directory is empty or not exist" $RED) + echo $(color_message "ERROR: 'data' directory is empty or not exist for. Please add '.gitkeep' file in 'data' folder if need" $RED) exit 1 fi diff --git a/simple_data_check.py b/simple_data_check.py index e293684..fb48b3b 100755 --- a/simple_data_check.py +++ b/simple_data_check.py @@ -141,7 +141,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], if len(vals) != 6: # YYYYMMDDT, o, h, l, c, v messages.append(F'{file_path}:{i} contains incorrect number of elements (expected: 6, actual: {len(vals)})') return messages, date - + check_ok = True # validate float try: @@ -151,7 +151,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], open_price, high_price, low_price, close_price, volume = float(vals[1]), float(vals[2]), float(vals[3]), float(vals[4]), float(vals[5]) except ValueError: check_ok = False - messages.append(F'{file_path}:{i} float values validation error. The float value can\'t be NAN/+INF/-INF') + messages.append(F'{file_path}:{i} float values validation error. The float value can\'t be NAN/+INF/-INF') # validate date try: if len(vals[0]) != 9: # value '202291T' is considered as correct date 2022/09/01 by datetime.strptime but specification require zero-padded values @@ -160,7 +160,7 @@ def check_data_line(data_line: str, file_path: str, i: int) -> Tuple[List[str], except (ValueError, TypeError): check_ok = False messages.append(F'{file_path}:{i} date validation error, date format have to be YYYYMMDDT, for example: 20230101T') - + if check_ok: date = vals[0] if not (open_price <= high_price >= close_price >= low_price <= open_price and high_price >= low_price): @@ -202,7 +202,10 @@ def check_data_files(sym_file_path: str, symbols: List[str], problems: Dict[str, if len(parts) != 2: problems["errors"].append(F'Invalid file name. Check that {file} has a valid name and extension.') continue - if parts[1] not in ("csv", "CSV"): + if parts[1] in {"gitkeep"}: + sym_set.discard(parts[0]) + continue + if parts[1] not in {"csv", "CSV"}: problems["errors"].append(F'Invalid file extension. The {file} file format must be CSV.') continue if parts[0] not in sym_set: @@ -244,15 +247,15 @@ def main() -> None: if len_problems_missed_files > 0: if len_problems_missed_files > MAX_ERRORS_IN_MSG + THRESHOLD_ERR: warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"][:MAX_ERRORS_IN_MSG])} and {len_problems_missed_files - MAX_ERRORS_IN_MSG} other CSV files.\n' - else: + else: warning = F'WARNING: the following symbols have no corresponding CSV files in the data folder: {", ".join(problems["missed_files"])}\n' - + if REPORTS_PATH is None: print(YEL+warning+ENDC) else: with open(os.path.join(REPORTS_PATH, "warnings.txt"), "a") as file: file.write(warning) - + # report errors len_problems_errors = len(problems["errors"]) if len_problems_errors > 0: @@ -262,7 +265,7 @@ def main() -> None: else: problems_list = "\n ".join(problems["errors"]) error_msg = F'ERROR: the following issues were found in the repository files:\n {problems_list}\n' - + fail(error_msg) From a24428b73baf383b0b4ae63f8b71c54e3b09bac1 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 21 Dec 2023 11:54:46 +0300 Subject: [PATCH 21/25] DF-2449: add dotglob --- check_data_and_create_pr.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 9d42380..858d1cb 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -23,6 +23,7 @@ color_message() { set -e # checkout fork repo (via temp dir as current dir is not emply and it does't allow to check out repo in it) git clone "https://${REPO_OWNER}:${ACTION_TOKEN}@github.com/${REPO_OWNER}/${REPO_NAME}.git" temp +shopt -s dotglob mv temp/* . mv temp//.git* . rmdir temp From 50eefea62ad21bd000fd64e7cf325bbfad450578 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 21 Dec 2023 12:57:00 +0300 Subject: [PATCH 22/25] DF-2449: upd code about dotglob --- check_data_and_create_pr.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 858d1cb..14e37bd 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -25,7 +25,6 @@ set -e git clone "https://${REPO_OWNER}:${ACTION_TOKEN}@github.com/${REPO_OWNER}/${REPO_NAME}.git" temp shopt -s dotglob mv temp/* . -mv temp//.git* . rmdir temp if [ ! -d "data" ]; then From e0066654e2db3c30c06fa7055094d32ccc3b46ca Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 21 Dec 2023 12:59:22 +0300 Subject: [PATCH 23/25] DF-2449: final state --- check_data_and_create_pr.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 14e37bd..3b2aaa3 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -30,9 +30,6 @@ rmdir temp if [ ! -d "data" ]; then echo $(color_message "ERROR: 'data' directory is empty or not exist for. Please add '.gitkeep' file in 'data' folder if need" $RED) exit 1 -elif [[ $(ls "data" | wc -l) -eq 0 ]]; then - echo $(color_message "ERROR: 'data' directory is empty or not exist for. Please add '.gitkeep' file in 'data' folder if need" $RED) - exit 1 fi set +e From 3838af408bdba43a290feee501f32b16240c11a7 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Thu, 21 Dec 2023 17:14:09 +0300 Subject: [PATCH 24/25] DF-2449: fix log typo --- check_data_and_create_pr.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 3b2aaa3..6bef4a6 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -28,7 +28,7 @@ mv temp/* . rmdir temp if [ ! -d "data" ]; then - echo $(color_message "ERROR: 'data' directory is empty or not exist for. Please add '.gitkeep' file in 'data' folder if need" $RED) + echo $(color_message "ERROR: 'data' directory is empty (for git) or not exist. Please add '.gitkeep' file in 'data' folder if need" $RED) exit 1 fi From 94ac14c627823d0c301b0a6fe7041d164c29bfa7 Mon Sep 17 00:00:00 2001 From: dpoliakov Date: Fri, 22 Dec 2023 16:40:12 +0300 Subject: [PATCH 25/25] DF-2449: remove total_branch var to avoid fatal from git --- check_data_and_create_pr.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/check_data_and_create_pr.sh b/check_data_and_create_pr.sh index 6bef4a6..962bd24 100755 --- a/check_data_and_create_pr.sh +++ b/check_data_and_create_pr.sh @@ -39,13 +39,16 @@ git checkout master git branch --list | cat merged_branches=$(git branch -r --merged | grep "update_*" -c) nomerged_branches=$(git branch -r --no-merged | grep "update_*" -c) -total_branches=$(($merged_branches+$nomerged_branches)) # delete all merged and unmerged remote `update_*` branches -if [[ $total_branches > 0 ]] +if [[ $merged_branches > 0 ]] then git branch -r --merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin - git branch -r --no-merged | grep "update_*" | cut -d "/" -f 2| xargs git push --delete origin +fi + +if [[ $nomerged_branches > 0 ]] +then + git branch -r --no-merged | grep "update_*" | cut -d "/" -f 2 | xargs git push --delete origin fi set -e