Skip to content

Commit

Permalink
ci: fix v15 tests
Browse files Browse the repository at this point in the history
  • Loading branch information
agritheory committed May 5, 2024
1 parent 7d9cc85 commit 6126e42
Show file tree
Hide file tree
Showing 34 changed files with 2,585 additions and 1,735 deletions.
11 changes: 11 additions & 0 deletions .backportrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"repoOwner": "agritheory",
"repoName": "cloud_storage",
"targetBranchChoices": ["version-14", "version-15"],
"targetBranches": ["version-14", "version-15"],
"autoMerge": true,
"autoMergeMethod": "squash",
"branchLabelMapping": {
"^auto-backport-to-(.+)$": "$1"
}
}
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ charset = utf-8
indent_style = tab
indent_size = 2
max_line_length = 99

# JSON files - mostly doctype schema files
[{*.json}]
insert_final_newline = false
indent_style = space
indent_size = 2
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cloud_storage/public/js/lib/*
cloud_storage/templates/includes/*
cloud_storage/www/website_script.js
124 changes: 124 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
"env": {
"browser": true,
"node": true,
"es2022": true
},
"parserOptions": {
"sourceType": "module"
},
"extends": "eslint:recommended",
"rules": {
"indent": "off",
"brace-style": "off",
"no-mixed-spaces-and-tabs": "off",
"no-useless-escape": "off",
"space-unary-ops": ["error", { "words": true }],
"linebreak-style": "off",
"quotes": ["off"],
"semi": "off",
"camelcase": "off",
"no-unused-vars": "off",
"no-console": ["warn"],
"no-extra-boolean-cast": ["off"],
"no-control-regex": ["off"]
},
"root": true,
"globals": {
"frappe": true,
"Vue": true,
"SetVueGlobals": true,
"__": true,
"repl": true,
"Class": true,
"locals": true,
"cint": true,
"cstr": true,
"cur_frm": true,
"cur_dialog": true,
"cur_page": true,
"cur_list": true,
"cur_tree": true,
"msg_dialog": true,
"is_null": true,
"in_list": true,
"has_common": true,
"posthog": true,
"has_words": true,
"validate_email": true,
"open_web_template_values_editor": true,
"validate_name": true,
"validate_phone": true,
"validate_url": true,
"get_number_format": true,
"format_number": true,
"format_currency": true,
"comment_when": true,
"open_url_post": true,
"toTitle": true,
"lstrip": true,
"rstrip": true,
"strip": true,
"strip_html": true,
"replace_all": true,
"flt": true,
"precision": true,
"CREATE": true,
"AMEND": true,
"CANCEL": true,
"copy_dict": true,
"get_number_format_info": true,
"strip_number_groups": true,
"print_table": true,
"Layout": true,
"web_form_settings": true,
"$c": true,
"$a": true,
"$i": true,
"$bg": true,
"$y": true,
"$c_obj": true,
"refresh_many": true,
"refresh_field": true,
"toggle_field": true,
"get_field_obj": true,
"get_query_params": true,
"unhide_field": true,
"hide_field": true,
"set_field_options": true,
"getCookie": true,
"getCookies": true,
"get_url_arg": true,
"md5": true,
"$": true,
"jQuery": true,
"moment": true,
"hljs": true,
"Awesomplete": true,
"Sortable": true,
"Showdown": true,
"Taggle": true,
"Gantt": true,
"Slick": true,
"Webcam": true,
"PhotoSwipe": true,
"PhotoSwipeUI_Default": true,
"io": true,
"JsBarcode": true,
"L": true,
"Chart": true,
"DataTable": true,
"Cypress": true,
"cy": true,
"it": true,
"describe": true,
"expect": true,
"context": true,
"before": true,
"beforeEach": true,
"after": true,
"qz": true,
"localforage": true,
"extend_cscript": true
}
}
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ ignore =
F841,
E713,
E712,
B028,

max-line-length = 200
exclude=,test_*.py
48 changes: 48 additions & 0 deletions .github/helper/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

set -e

cd ~ || exit

sudo apt update
sudo apt remove mysql-server mysql-client
sudo apt install libcups2-dev redis-server mariadb-client-10.6

pip install frappe-bench

bench init --skip-redis-config-generation --skip-assets --python "$(which python)" --frappe-branch version-15 frappe-bench

mkdir ~/frappe-bench/sites/test_site
cp -r "${GITHUB_WORKSPACE}/.github/helper/site_config.json" ~/frappe-bench/sites/test_site/

mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'"
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE DATABASE test_frappe"
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "FLUSH PRIVILEGES"

install_whktml() {
wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
sudo chmod o+x /usr/local/bin/wkhtmltopdf
}
install_whktml &

cd ~/frappe-bench || exit

sed -i 's/watch:/# watch:/g' Procfile
sed -i 's/schedule:/# schedule:/g' Procfile
sed -i 's/socketio:/# socketio:/g' Procfile
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile

bench get-app erpnext --branch "version-15" --resolve-deps
bench get-app cloud_storage "${GITHUB_WORKSPACE}"
bench setup requirements --dev

bench start &> bench_run_logs.txt &
CI=Yes bench build --app frappe &

bench --site test_site reinstall --yes
bench --site test_site install-app cloud_storage
19 changes: 19 additions & 0 deletions .github/helper/site_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"db_host": "127.0.0.1",
"db_port": 3306,
"db_name": "test_frappe",
"db_password": "test_frappe",
"allow_tests": true,
"db_type": "mariadb",
"auto_email_id": "[email protected]",
"mail_server": "localhost",
"mail_port": 2525,
"mail_login": "[email protected]",
"mail_password": "test",
"admin_password": "admin",
"root_login": "root",
"root_password": "root",
"host_name": "http://test_site:8000",
"monitor": 1,
"server_script_enabled": true
}
164 changes: 164 additions & 0 deletions .github/validate_customizations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import json
import pathlib
import sys


def scrub(txt: str) -> str:
return txt.replace(" ", "_").replace("-", "_").lower()


def unscrub(txt: str) -> str:
return txt.replace("_", " ").replace("-", " ").title()


def get_customized_doctypes():
apps_dir = pathlib.Path(__file__).resolve().parent.parent.parent
apps_order = pathlib.Path(__file__).resolve().parent.parent.parent.parent / "sites" / "apps.txt"
apps_order = apps_order.read_text().split("\n")
customized_doctypes = {}
for _app_dir in apps_order:
app_dir = (apps_dir / _app_dir).resolve()
if not app_dir.is_dir():
continue
modules = (app_dir / _app_dir / "modules.txt").read_text().split("\n")
for module in modules:
if not (app_dir / _app_dir / scrub(module) / "custom").exists():
continue
for custom_file in list((app_dir / _app_dir / scrub(module) / "custom").glob("**/*.json")):
if custom_file.stem in customized_doctypes:
customized_doctypes[custom_file.stem].append(custom_file.resolve())
else:
customized_doctypes[custom_file.stem] = [custom_file.resolve()]

return dict(sorted(customized_doctypes.items()))


def validate_module(customized_doctypes, set_module=False):
exceptions = []
app_dir = pathlib.Path(__file__).resolve().parent.parent
this_app = app_dir.stem
for doctype, customize_files in customized_doctypes.items():
for customize_file in customize_files:
if not this_app in str(customize_file):
continue
module = customize_file.parent.parent.stem
file_contents = json.loads(customize_file.read_text())
if file_contents.get("custom_fields"):
for custom_field in file_contents.get("custom_fields"):
if set_module:
custom_field["module"] = unscrub(module)
continue
if not custom_field.get("module"):
exceptions.append(
f"Custom Field for {custom_field.get('dt')} in {this_app} '{custom_field.get('fieldname')}' does not have a module key"
)
continue
elif custom_field.get("module") != unscrub(module):
exceptions.append(
f"Custom Field for {custom_field.get('dt')} in {this_app} '{custom_field.get('fieldname')}' has module key ({custom_field.get('module')}) associated with another app"
)
continue
if file_contents.get("property_setters"):
for ps in file_contents.get("property_setters"):
if set_module:
ps["module"] = unscrub(module)
continue
if not ps.get("module"):
exceptions.append(
f"Property Setter for {ps.get('doc_type')} in {this_app} '{ps.get('property')}' on {ps.get('field_name')} does not have a module key"
)
continue
elif ps.get("module") != unscrub(module):
exceptions.append(
f"Property Setter for {ps.get('doc_type')} in {this_app} '{ps.get('property')}' on {ps.get('field_name')} has module key ({ps.get('module')}) associated with another app"
)
continue
if set_module:
with customize_file.open("w", encoding="UTF-8") as target:
json.dump(file_contents, target, sort_keys=True, indent=2)

return exceptions


def validate_no_custom_perms(customized_doctypes):
exceptions = []
this_app = pathlib.Path(__file__).resolve().parent.parent.stem
for doctype, customize_files in customized_doctypes.items():
for customize_file in customize_files:
if not this_app in str(customize_file):
continue
file_contents = json.loads(customize_file.read_text())
if file_contents.get("custom_perms"):
exceptions.append(f"Customization for {doctype} in {this_app} contains custom permissions")
return exceptions


def validate_duplicate_customizations(customized_doctypes):
exceptions = []
common_fields = {}
common_property_setters = {}
app_dir = pathlib.Path(__file__).resolve().parent.parent
this_app = app_dir.stem
for doctype, customize_files in customized_doctypes.items():
if len(customize_files) == 1:
continue
common_fields[doctype] = {}
common_property_setters[doctype] = {}
for customize_file in customize_files:
module = customize_file.parent.parent.stem
app = customize_file.parent.parent.parent.parent.stem
file_contents = json.loads(customize_file.read_text())
if file_contents.get("custom_fields"):
fields = [cf.get("fieldname") for cf in file_contents.get("custom_fields")]
common_fields[doctype][module] = fields
if file_contents.get("property_setters"):
ps = [ps.get("name") for ps in file_contents.get("property_setters")]
common_property_setters[doctype][module] = ps

for doctype, module_and_fields in common_fields.items():
if this_app not in module_and_fields.keys():
continue
this_modules_fields = module_and_fields.pop(this_app)
for module, fields in module_and_fields.items():
for field in fields:
if field in this_modules_fields:
exceptions.append(
f"Custom Field for {unscrub(doctype)} in {this_app} '{field}' also appears in customizations for {module}"
)

for doctype, module_and_ps in common_property_setters.items():
if this_app not in module_and_ps.keys():
continue
this_modules_ps = module_and_ps.pop(this_app)
for module, ps in module_and_ps.items():
for p in ps:
if p in this_modules_ps:
exceptions.append(
f"Property Setter for {unscrub(doctype)} in {this_app} on '{p}' also appears in customizations for {module}"
)

return exceptions


def validate_customizations(set_module):
customized_doctypes = get_customized_doctypes()
exceptions = validate_no_custom_perms(customized_doctypes)
exceptions += validate_module(customized_doctypes, set_module)
exceptions += validate_duplicate_customizations(customized_doctypes)

return exceptions


if __name__ == "__main__":
exceptions = []
set_module = False
for arg in sys.argv:
if arg == "--set-module":
set_module = True
exceptions.append(validate_customizations(set_module))

if exceptions:
for exception in exceptions:
[print(e) for e in exception] # TODO: colorize

sys.exit(1) if all(exceptions) else sys.exit(0)
Loading

0 comments on commit 6126e42

Please sign in to comment.