From 95d0fb57cd0bc2eb0b4dbce6669db69d0b9ebc07 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 14 Jan 2024 17:36:47 +0100 Subject: [PATCH] feat: linter workflow for new apps --- .github/workflows/linters.yml | 1 + frappe/utils/boilerplate.py | 88 +++++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 8b35471d0c..5c7f33e87d 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -1,3 +1,4 @@ +# When updating this file, please also update the linter_workflow_template in frappe/utils/boilerplate.py name: Linters on: diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 88d96f41c7..8f0c6431c3 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -157,9 +157,6 @@ def _create_app_boilerplate(dest, hooks, no_git=False): with open(os.path.join(dest, hooks.app_name, ".pre-commit-config.yaml"), "w") as f: f.write(frappe.as_unicode(precommit_template.format(**hooks))) - with open(os.path.join(dest, hooks.app_name, "README.md"), "w") as f: - f.write(frappe.as_unicode(readme_template.format(**hooks))) - license_body = get_license_text(license_name=hooks.app_license) with open(os.path.join(dest, hooks.app_name, "license.txt"), "w") as f: f.write(frappe.as_unicode(license_body)) @@ -186,6 +183,12 @@ def _create_app_boilerplate(dest, hooks, no_git=False): if hooks.create_github_workflow: _create_github_workflow_files(dest, hooks) + hooks.readme_ci_section = readme_ci_section + else: + hooks.readme_ci_section = "" + + with open(os.path.join(dest, hooks.app_name, "README.md"), "w") as f: + f.write(frappe.as_unicode(readme_template.format(**hooks))) if not no_git: with open(os.path.join(dest, hooks.app_name, ".gitignore"), "w") as f: @@ -207,6 +210,10 @@ def _create_github_workflow_files(dest, hooks): with open(ci_workflow, "w") as f: f.write(github_workflow_template.format(**hooks)) + linter_workflow = workflows_path / "linter.yml" + with open(linter_workflow, "w") as f: + f.write(linter_workflow_template) + PATCH_TEMPLATE = textwrap.dedent( ''' @@ -771,6 +778,69 @@ ci: submodules: false """ +linter_workflow_template = """ +name: Linters + +on: + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + linter: + name: 'Frappe Linter' + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: pip + - uses: pre-commit/action@v3.0.0 + + - name: Download Semgrep rules + run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules + + - name: Run Semgrep rules + run: | + pip install semgrep + semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness + + deps-vulnerable-check: + name: 'Vulnerable Dependency Check' + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - uses: actions/checkout@v4 + + - name: Cache pip + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml', '**/setup.py') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Install and run pip-audit + run: | + pip install pip-audit + cd ${GITHUB_WORKSPACE} + pip-audit --desc on . +""" + readme_template = """### {app_title} {app_description} @@ -802,8 +872,18 @@ Pre-commit is configured to use the following tools for checking and formatting - eslint - prettier - pyupgrade - +{readme_ci_section} ### License {app_license} """ + +readme_ci_section = """ +### CI + +This app can use GitHub Actions for CI. The following workflows are configured: + +- CI: Installs this app and runs unit tests on every push to `develop` branch. +- Linters: Runs [Frappe Semgrep Rules](https://github.com/frappe/semgrep-rules) and [pip-audit](https://pypi.org/project/pip-audit/) on every pull request. + +"""