Browse Source
* chore: Add GA for translation syntax validation * chore: Documentation link checker Co-authored-by: Gavin D'souza <gavin18d@gmail.com> * fix: URL Co-authored-by: Nabin Hait <nabinhait@gmail.com> Co-authored-by: Gavin D'souza <gavin18d@gmail.com> Co-authored-by: Nabin Hait <nabinhait@gmail.com>develop
Suraj Shetty
4 years ago
committed by
GitHub
4 changed files with 154 additions and 0 deletions
@ -0,0 +1,48 @@ |
|||
import sys |
|||
import requests |
|||
from urllib.parse import urlparse |
|||
|
|||
|
|||
docs_repos = [ |
|||
"frappe_docs", |
|||
"erpnext_documentation", |
|||
"erpnext_com", |
|||
"frappe_io", |
|||
] |
|||
|
|||
|
|||
def uri_validator(x): |
|||
result = urlparse(x) |
|||
return all([result.scheme, result.netloc, result.path]) |
|||
|
|||
def docs_link_exists(body): |
|||
for line in body.splitlines(): |
|||
for word in line.split(): |
|||
if word.startswith('http') and uri_validator(word): |
|||
parsed_url = urlparse(word) |
|||
if parsed_url.netloc == "github.com": |
|||
_, org, repo, _type, ref = parsed_url.path.split('/') |
|||
if org == "frappe" and repo in docs_repos: |
|||
return True |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
pr = sys.argv[1] |
|||
response = requests.get("https://api.github.com/repos/frappe/erpnext/pulls/{}".format(pr)) |
|||
|
|||
if response.ok: |
|||
payload = response.json() |
|||
title = payload.get("title", "").lower() |
|||
head_sha = payload.get("head", {}).get("sha") |
|||
body = payload.get("body", "").lower() |
|||
|
|||
if title.startswith("feat") and head_sha and "no-docs" not in body: |
|||
if docs_link_exists(body): |
|||
print("Documentation Link Found. You're Awesome! 🎉") |
|||
|
|||
else: |
|||
print("Documentation Link Not Found! ⚠️") |
|||
sys.exit(1) |
|||
|
|||
else: |
|||
print("Skipping documentation checks... 🏃") |
@ -0,0 +1,60 @@ |
|||
import re |
|||
import sys |
|||
|
|||
errors_encounter = 0 |
|||
pattern = re.compile(r"_\(([\"']{,3})(?P<message>((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P<py_context>((?!\5).)*)\5)*(\s*,\s*(.)*?\s*(,\s*([\"'])(?P<js_context>((?!\11).)*)\11)*)*\)") |
|||
words_pattern = re.compile(r"_{1,2}\([\"'`]{1,3}.*?[a-zA-Z]") |
|||
start_pattern = re.compile(r"_{1,2}\([f\"'`]{1,3}") |
|||
f_string_pattern = re.compile(r"_\(f[\"']") |
|||
starts_with_f_pattern = re.compile(r"_\(f") |
|||
|
|||
# skip first argument |
|||
files = sys.argv[1:] |
|||
files_to_scan = [_file for _file in files if _file.endswith(('.py', '.js'))] |
|||
|
|||
for _file in files_to_scan: |
|||
with open(_file, 'r') as f: |
|||
print(f'Checking: {_file}') |
|||
file_lines = f.readlines() |
|||
for line_number, line in enumerate(file_lines, 1): |
|||
if 'frappe-lint: disable-translate' in line: |
|||
continue |
|||
|
|||
start_matches = start_pattern.search(line) |
|||
if start_matches: |
|||
starts_with_f = starts_with_f_pattern.search(line) |
|||
|
|||
if starts_with_f: |
|||
has_f_string = f_string_pattern.search(line) |
|||
if has_f_string: |
|||
errors_encounter += 1 |
|||
print(f'\nF-strings are not supported for translations at line number {line_number + 1}\n{line.strip()[:100]}') |
|||
continue |
|||
else: |
|||
continue |
|||
|
|||
match = pattern.search(line) |
|||
error_found = False |
|||
|
|||
if not match and line.endswith(',\n'): |
|||
# concat remaining text to validate multiline pattern |
|||
line = "".join(file_lines[line_number - 1:]) |
|||
line = line[start_matches.start() + 1:] |
|||
match = pattern.match(line) |
|||
|
|||
if not match: |
|||
error_found = True |
|||
print(f'\nTranslation syntax error at line number {line_number + 1}\n{line.strip()[:100]}') |
|||
|
|||
if not error_found and not words_pattern.search(line): |
|||
error_found = True |
|||
print(f'\nTranslation is useless because it has no words at line number {line_number + 1}\n{line.strip()[:100]}') |
|||
|
|||
if error_found: |
|||
errors_encounter += 1 |
|||
|
|||
if errors_encounter > 0: |
|||
print('\nVisit "https://frappeframework.com/docs/user/en/translations" to learn about valid translation strings.') |
|||
sys.exit(1) |
|||
else: |
|||
print('\nGood To Go!') |
@ -0,0 +1,24 @@ |
|||
name: 'Documentation Required' |
|||
on: |
|||
pull_request: |
|||
types: [ opened, synchronize, reopened, edited ] |
|||
|
|||
jobs: |
|||
build: |
|||
runs-on: ubuntu-latest |
|||
|
|||
steps: |
|||
- name: 'Setup Environment' |
|||
uses: actions/setup-python@v2 |
|||
with: |
|||
python-version: 3.6 |
|||
|
|||
- name: 'Clone repo' |
|||
uses: actions/checkout@v2 |
|||
|
|||
- name: Validate Docs |
|||
env: |
|||
PR_NUMBER: ${{ github.event.number }} |
|||
run: | |
|||
pip install requests --quiet |
|||
python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER |
@ -0,0 +1,22 @@ |
|||
name: Frappe Linter |
|||
on: |
|||
pull_request: |
|||
branches: |
|||
- develop |
|||
- version-12-hotfix |
|||
- version-11-hotfix |
|||
jobs: |
|||
check_translation: |
|||
name: Translation Syntax Check |
|||
runs-on: ubuntu-18.04 |
|||
steps: |
|||
- uses: actions/checkout@v2 |
|||
- name: Setup python3 |
|||
uses: actions/setup-python@v1 |
|||
with: |
|||
python-version: 3.6 |
|||
- name: Validating Translation Syntax |
|||
run: | |
|||
git fetch origin $GITHUB_BASE_REF:$GITHUB_BASE_REF -q |
|||
files=$(git diff --name-only --diff-filter=d $GITHUB_BASE_REF) |
|||
python $GITHUB_WORKSPACE/.github/helper/translation.py $files |
Loading…
Reference in new issue