From 5c7500b72fea46a89889745618829599839e089d Mon Sep 17 00:00:00 2001 From: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:25:29 +0530 Subject: [PATCH 1/4] ci: add bench build, linters, gitleaks and conventional commits workflows Ref: https://github.com/rtCamp/support/issues/797 Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --- .github/workflows/build-test.yml | 58 ++++++++++++++++++++++++++ .github/workflows/gitleaks.yml | 26 ++++++++++++ .github/workflows/linters.yml | 52 +++++++++++++++++++++++ .github/workflows/semantic-commits.yml | 28 +++++++++++++ commitlint.config.js | 13 ++++++ 5 files changed, 177 insertions(+) create mode 100644 .github/workflows/build-test.yml create mode 100644 .github/workflows/gitleaks.yml create mode 100644 .github/workflows/linters.yml create mode 100644 .github/workflows/semantic-commits.yml create mode 100644 commitlint.config.js diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000..a07cbc8 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,58 @@ +name: Bench Build Test + +on: + pull_request: + +concurrency: + group: ${{ github.repository }}-${{ github.event.number }} + cancel-in-progress: true + +jobs: + Bench-Build-Test: + runs-on: self-hosted + container: + image: docker.io/frappe/bench:latest + options: --user root + + steps: + - name: Setup Github ENV + run: | + echo "HOME=/home/frappe" >> $GITHUB_ENV + echo "PATH=/home/frappe/.local/bin:$PATH" >> $GITHUB_ENV + + - name: Create a new minimal bench + run: | + cd /home/frappe + su frappe bash -c "bench init frappe-bench --skip-redis-config-generation --no-procfile --skip-assets" + + - name: Get Dependent Apps + run: | + cd /home/frappe/frappe-bench + # Use public URL for public repos, authenticated URL for private repos + if [ "${{ github.event.pull_request.head.repo.private }}" = "false" ]; then + # This is a public repository (could be a fork or not) + git clone https://github.com/${{ github.event.pull_request.head.repo.full_name }} -b ${{ github.event.pull_request.head.ref }} --depth=1 app_repo + else + # Private repository, use authentication + git clone https://rtbot:${{ secrets.RTBOT_TOKEN }}@github.com/${{ github.event.pull_request.head.repo.full_name }} -b ${{ github.event.pull_request.head.ref }} --depth=1 app_repo + fi + DEPS=$(grep -E "required_apps\s*=\s*\[" app_repo/*/hooks.py | sed 's/.*\[\(.*\)\]/\1/g' | tr -d '"' | tr -d "'" | tr ',' '\n' | awk '{$1=$1};1') + rm -rf app_repo + for dep in $DEPS; do + su frappe bash -c "bench get-app $dep" + done + + - name: Get APP and Build + run: | + cd /home/frappe/frappe-bench + if [ "${{ github.event.pull_request.head.repo.private }}" = "false" ]; then + # Public fork + su frappe bash -c "bench get-app https://github.com/${{ github.event.pull_request.head.repo.full_name }} --branch ${{ github.event.pull_request.head.ref }}" + else + # Private fork (requires token) + su frappe bash -c "bench get-app https://rtbot:${{ secrets.RTBOT_TOKEN }}@github.com/${{ github.event.pull_request.head.repo.full_name }} --branch ${{ github.event.pull_request.head.ref }}" + fi + + - name: Cleanup + if: ${{ always() }} + uses: rtCamp/action-cleanup@master \ No newline at end of file diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 0000000..df18c08 --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,26 @@ +name: Gitleaks + +on: + push: + branches: + - version-16 + - version-16-hotfix + pull_request: + branches: + - version-16 + - version-16-hotfix + +jobs: + gitleaks: + name: Gitleaks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Run Gitleaks + uses: gitleaks/gitleaks-action@v3 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..dae7976 --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,52 @@ +name: Linters + +on: + pull_request: + workflow_dispatch: +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + pre-commit: + name: "Frappe Linter" + runs-on: self-hosted + container: + image: alpine:latest # latest used here for simplicity, not recommended + defaults: + run: + shell: sh + steps: + - name: fix tar dependency in alpine container image + run: | + apk --no-cache add tar nodejs npm python3 git bash py3-pip + npm install -g prettier + # check python modules installed versions + python3 -m pip freeze --local + pip install pre-commit --break-system-packages + + - uses: actions/checkout@v6 + - run: | + git config --global --add safe.directory $GITHUB_WORKSPACE + git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* + + - name: Get changed files + id: file_changes + run: | + export DIFF=$(git diff --name-only origin/${{ github.base_ref }} ${{ github.sha }}) + echo "Diff between ${{ github.base_ref }} and ${{ github.sha }}" + echo "files=$( echo "$DIFF" | xargs echo )" >> $GITHUB_OUTPUT + + + - name: Cache pre-commit since we use pre-commit from container + uses: actions/cache@v5 + with: + path: ~/.cache/pre-commit + key: pre-commit-3|${{ hashFiles('.pre-commit-config.yaml') }} + + - name: Execute pre-commit + run: | + pre-commit run --color=always --show-diff-on-failure --files ${{ steps.file_changes.outputs.files }} diff --git a/.github/workflows/semantic-commits.yml b/.github/workflows/semantic-commits.yml new file mode 100644 index 0000000..577c9b5 --- /dev/null +++ b/.github/workflows/semantic-commits.yml @@ -0,0 +1,28 @@ +name: Semantic Commits + +on: + pull_request: + +jobs: + commitlint: + name: Semantic Commits + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install commitlint + run: npm install --no-save @commitlint/cli @commitlint/config-conventional + + - name: Check commit titles + run: >- + npx commitlint --verbose + --from ${{ github.event.pull_request.base.sha }} + --to ${{ github.event.pull_request.head.sha }} diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..5670209 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,13 @@ +module.exports = { + parserPreset: "conventional-changelog-conventionalcommits", + rules: { + "subject-empty": [2, "never"], + "type-case": [2, "always", "lower-case"], + "type-empty": [2, "never"], + "type-enum": [ + 2, + "always", + ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"], + ], + }, +}; From 6a3d4cc3ac5f066a16dada472bcdfa7c0899f333 Mon Sep 17 00:00:00 2001 From: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:51:00 +0530 Subject: [PATCH 2/4] fix: format commitlint.config.js for prettier compatibility Ref: https://github.com/rtCamp/support/issues/797 Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --- commitlint.config.js | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/commitlint.config.js b/commitlint.config.js index 5670209..bd5cebc 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,13 +1,25 @@ module.exports = { - parserPreset: "conventional-changelog-conventionalcommits", - rules: { - "subject-empty": [2, "never"], - "type-case": [2, "always", "lower-case"], - "type-empty": [2, "never"], - "type-enum": [ - 2, - "always", - ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"], - ], - }, + parserPreset: "conventional-changelog-conventionalcommits", + rules: { + "subject-empty": [2, "never"], + "type-case": [2, "always", "lower-case"], + "type-empty": [2, "never"], + "type-enum": [ + 2, + "always", + [ + "build", + "chore", + "ci", + "docs", + "feat", + "fix", + "perf", + "refactor", + "revert", + "style", + "test", + ], + ], + }, }; From 672b66c01996824b16d91828e0aa6d4810a63dc5 Mon Sep 17 00:00:00 2001 From: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> Date: Tue, 16 Jun 2026 18:55:27 +0530 Subject: [PATCH 3/4] fix: use ubuntu-latest runner for bench build and linters Ref: https://github.com/rtCamp/support/issues/797 Signed-off-by: Dipankar Das <65275144+dipankardas011@users.noreply.github.com> --- .github/workflows/build-test.yml | 2 +- .github/workflows/linters.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index a07cbc8..5d53bff 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -9,7 +9,7 @@ concurrency: jobs: Bench-Build-Test: - runs-on: self-hosted + runs-on: ubuntu-latest container: image: docker.io/frappe/bench:latest options: --user root diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index dae7976..ece57ff 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -13,7 +13,7 @@ concurrency: jobs: pre-commit: name: "Frappe Linter" - runs-on: self-hosted + runs-on: ubuntu-latest container: image: alpine:latest # latest used here for simplicity, not recommended defaults: From 26fbcf0ca2b61c36028b538ab56f10d1f2e7aac0 Mon Sep 17 00:00:00 2001 From: Niraj Gautam Date: Thu, 18 Jun 2026 13:21:26 +0530 Subject: [PATCH 4/4] fix: Resolve semgrep issue --- eslint.config.js | 2 +- frappe_openapi/frappe_openapi/generate_api_docs.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index b8404cb..a3f075e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,4 +5,4 @@ export default [ sourceType: "module", }, }, -]; \ No newline at end of file +]; diff --git a/frappe_openapi/frappe_openapi/generate_api_docs.py b/frappe_openapi/frappe_openapi/generate_api_docs.py index 5a4663d..4f02ae5 100644 --- a/frappe_openapi/frappe_openapi/generate_api_docs.py +++ b/frappe_openapi/frappe_openapi/generate_api_docs.py @@ -59,7 +59,7 @@ def extract_returns_from_docstring(docstring): def parse_functions_from_file(file_path): - with open(file_path, encoding="utf-8") as f: + with open(file_path, encoding="utf-8") as f: # nosemgrep schema is in json file which needs to be read. tree = ast.parse(f.read(), filename=file_path) return [ { @@ -193,7 +193,7 @@ def generate_openapi_for_all_apps(): openapi["info"]["version"] = app_version output_file = os.path.join(public_folder, f"openapi_{app_name}.json") try: - with open(output_file, "w", encoding="utf-8") as f: + with open(output_file, "w", encoding="utf-8") as f: # nosemgrep schema needs to be written. json.dump(openapi, f, indent=2) update_progress_bar("Generating OpenAPI spec", i, total) except Exception as e: