From e844854ba6d72bbdc3af36e45ede13f2e0de0edd Mon Sep 17 00:00:00 2001 From: Ermoshkin Artem <94714022+Shfdis@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:27:57 +0300 Subject: create a dependency leak check helper (#45139) Co-authored-by: Artem Ermoshkin --- .github/workflows/cpp_sdk_peerdirs_check.yml | 68 +++++++++++++++++++ ydb/public/sdk/cpp/allowed_peerdirs.txt | 6 ++ ydb/public/sdk/cpp/scripts/check_peerdirs.py | 85 ++++++++++++++++++++++++ ydb/public/sdk/cpp/src/client/topic/impl/ya.make | 1 - 4 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/cpp_sdk_peerdirs_check.yml create mode 100644 ydb/public/sdk/cpp/allowed_peerdirs.txt create mode 100644 ydb/public/sdk/cpp/scripts/check_peerdirs.py diff --git a/.github/workflows/cpp_sdk_peerdirs_check.yml b/.github/workflows/cpp_sdk_peerdirs_check.yml new file mode 100644 index 00000000000..ad124c0c8fc --- /dev/null +++ b/.github/workflows/cpp_sdk_peerdirs_check.yml @@ -0,0 +1,68 @@ +name: Check CPP SDK PEERDIRs + +on: + pull_request_target: + branches: [main, stable-*] + paths: ['ydb/public/sdk/cpp/**', '.github/workflows/cpp_sdk_peerdirs_check.yml'] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + check: + if: >- + github.event_name == 'workflow_dispatch' || + (vars.CHECKS_SWITCH != '' && fromJSON(vars.CHECKS_SWITCH).cpp_sdk_peerdirs_check == true) + runs-on: [self-hosted, tiny-worker] + steps: + - uses: actions/github-script@v8 + if: github.event_name == 'pull_request_target' + id: gate + with: + github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + script: | + const pr = context.payload.pull_request; + if (pr.labels.some(l => l.name === 'ok-to-test')) return true; + if (pr.user.login === context.repo.owner) return true; + try { + await github.rest.repos.checkCollaborator({ + owner: context.repo.owner, repo: context.repo.repo, username: pr.user.login, + }); + return true; + } catch (e) { + if (e.status === 404) return false; + throw e; + } + + - name: Comment if waiting on ok-to-test + if: steps.gate.outputs.result == 'false' && github.event.action == 'opened' + uses: actions/github-script@v8 + with: + script: | + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Hi! The C++ SDK PEERDIRs check will run after a maintainer adds an `ok-to-test` label to this PR. Thank you for your patience!' + }); + + - uses: actions/checkout@v5 + if: github.event_name != 'pull_request_target' || steps.gate.outputs.result == 'true' + with: + ref: ${{ github.event.pull_request.head.sha || github.ref }} + fetch-depth: 0 + + - if: github.event_name != 'pull_request_target' || steps.gate.outputs.result == 'true' + env: + BASE_REF: ${{ github.event.pull_request.base.ref }} + run: | + set -euo pipefail + if [ "${{ github.event_name }}" = pull_request_target ]; then + git fetch --no-tags origin "$BASE_REF" + git diff --name-only --diff-filter=ACMRT "origin/$BASE_REF...HEAD" > changed.txt + python3 ydb/public/sdk/cpp/scripts/check_peerdirs.py changed.txt + else + python3 ydb/public/sdk/cpp/scripts/check_peerdirs.py + fi diff --git a/ydb/public/sdk/cpp/allowed_peerdirs.txt b/ydb/public/sdk/cpp/allowed_peerdirs.txt new file mode 100644 index 00000000000..49259c99a74 --- /dev/null +++ b/ydb/public/sdk/cpp/allowed_peerdirs.txt @@ -0,0 +1,6 @@ +# Mirrors ydb-cpp-sdk/.github/scripts/copy_sources.sh. +ydb/public/sdk/cpp/ +ydb/public/api/ +library/cpp/ +contrib/ +util/ diff --git a/ydb/public/sdk/cpp/scripts/check_peerdirs.py b/ydb/public/sdk/cpp/scripts/check_peerdirs.py new file mode 100644 index 00000000000..0ec91d0b4c6 --- /dev/null +++ b/ydb/public/sdk/cpp/scripts/check_peerdirs.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +import sys +from pathlib import Path + +SDK = Path(__file__).resolve().parent.parent +PREFIX = Path("ydb/public/sdk/cpp") +ALLOWLIST = SDK / "allowed_peerdirs.txt" +ALLOWED = [ + line.split("#", 1)[0].strip() + for line in ALLOWLIST.read_text(encoding="utf-8").splitlines() + if line.split("#", 1)[0].strip() +] +IN_SCOPE = {"src", "include", "plugins", "examples"} + + +def ok(rel): + parts = Path(rel).parts + return ( + parts + and parts[0] in IN_SCOPE + and "ut" not in parts + and "ut_utils" not in parts + ) + + +def peerdirs(text): + in_block = False + for i, line in enumerate(text.splitlines(), 1): + s = line.split("#", 1)[0].strip() + if s.startswith("PEERDIR("): + if s.endswith(")"): + dep = s[len("PEERDIR("):-1].strip() + if dep: + yield i, dep + else: + in_block = True + continue + if in_block: + if s == ")": + in_block = False + elif s: + yield i, s + + +def targets(changed_path): + all_targets = [ + p for p in sorted(SDK.rglob("ya.make")) if ok(p.relative_to(SDK)) + ] + if not changed_path: + return all_targets + changed = [ + Path(line.strip()) + for line in Path(changed_path).read_text(encoding="utf-8").splitlines() + if line.strip() + ] + if PREFIX / "allowed_peerdirs.txt" in changed or PREFIX / "scripts/check_peerdirs.py" in changed: + return all_targets + out = [] + for path in changed: + try: + rel = path.relative_to(PREFIX) + except ValueError: + continue + if path.name != "ya.make" or not ok(rel): + continue + out.append(SDK / rel) + return out + + +def main(): + files = targets(sys.argv[1] if len(sys.argv) > 1 else None) + bad = [] + for ya_make in files: + for line_no, dep in peerdirs(ya_make.read_text(encoding="utf-8")): + if not any(dep.startswith(p) for p in ALLOWED): + rel = PREFIX / ya_make.relative_to(SDK) + bad.append(f"{rel}:{line_no}: forbidden PEERDIR {dep!r}") + if bad: + print("\n".join(bad), file=sys.stderr) + raise SystemExit(1) + print(f"ok ({len(files)} ya.make)") + + +if __name__ == "__main__": + main() diff --git a/ydb/public/sdk/cpp/src/client/topic/impl/ya.make b/ydb/public/sdk/cpp/src/client/topic/impl/ya.make index cac04e3c63a..0cf913bf647 100644 --- a/ydb/public/sdk/cpp/src/client/topic/impl/ya.make +++ b/ydb/public/sdk/cpp/src/client/topic/impl/ya.make @@ -33,7 +33,6 @@ PEERDIR( library/cpp/threading/future/subscription library/cpp/monlib/metrics library/cpp/string_utils/url - ydb/library/persqueue ydb/public/sdk/cpp/src/library/persqueue/obfuscate ydb/public/api/grpc/draft ydb/public/api/grpc -- cgit v1.3