bitflicker64 commented on code in PR #3271: URL: https://github.com/apache/hugegraph/pull/3271#discussion_r4187729414
########## .github/scripts/ci-policy.py: ########## @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Conservative CI selection and GitHub-verified test receipt reuse.""" + +import argparse +import hashlib +import io +import json +import os +from pathlib import Path +import subprocess +import zipfile +from urllib.parse import urlencode + +MODULES = { + "server": ["server", "commons", "struct", "pd", "store", "hstore", "cluster", "docker", "helm", "dependency_license"], + "toolchain": ["client", "loader", "tools", "spark", "hubble", "go"], +} +PREFIXES = { + "server": {"hugegraph-server/": "server", "hugegraph-commons/": "commons", + "hugegraph-struct/": "struct", "hugegraph-pd/": "pd", "hugegraph-store/": "store", + "hugegraph-cluster-test/": "cluster", "docker/": "docker", "helm/": "helm"}, + "toolchain": {"hugegraph-client/": "client", "hugegraph-client-go/": "go", + "hugegraph-loader/": "loader", "hugegraph-tools/": "tools", + "hugegraph-spark-connector/": "spark", "hugegraph-hubble/": "hubble"}, +} +WORKFLOWS = { + "server": {"server-ci.yml": ["server"], "commons-ci.yml": ["commons"], + "pd-store-ci.yml": ["pd", "store", "hstore"], "cluster-test-ci.yml": ["cluster"], + "docker-build-ci.yml": ["docker"], "helm-chart-ci.yml": ["helm"], + "codeql-analysis.yml": [], "riscv64-ci.yml": ["server"], "check-dependencies.yml": ["dependency_license"]}, + "toolchain": {"client-ci.yml": ["client"], "client-go-ci.yml": ["go"], + "loader-ci.yml": ["loader"], "tools-ci.yml": ["tools"], + "spark-connector-ci.yml": ["spark"], "hubble-ci.yml": ["hubble"], + "codeql-analysis.yml": []}, +} +DEPENDENTS = { + "server": {"commons": ["server", "pd", "store", "hstore", "cluster"], + "struct": ["server", "pd", "store", "hstore", "cluster"], + "server": ["cluster"], "pd": ["store", "hstore", "cluster"], + "store": ["hstore", "cluster"], "hstore": ["cluster"]}, + "toolchain": {"client": ["loader", "tools", "spark", "hubble"], "loader": ["hubble"]}, +} + + +def git(*args): + return subprocess.check_output(["git", *args], text=True).strip() + + +def api(path, binary=False): + result = subprocess.run(["gh", "api", "--method", "GET", path], check=True, capture_output=True, timeout=30) + return result.stdout if binary else json.loads(result.stdout) + + +def documentation(path, mode="100644"): + """Only prose and static documentation assets; never source or config.""" + if mode != "100644": + return False + p = Path(path) + prose_names = {"README.md", "README_CN.md", "README_ZH.md", "AGENTS.md"} + module_roots = {prefix.rstrip("/") for mapping in PREFIXES.values() for prefix in mapping} + module_roots.update("hugegraph-server/" + module for module in [ + "hugegraph-api", "hugegraph-core", "hugegraph-dist", "hugegraph-example", + "hugegraph-hbase", "hugegraph-hstore", "hugegraph-rocksdb", "hugegraph-test"]) + if p.name in prose_names and (str(p.parent) == "." or str(p.parent) in module_roots): + return True + return path.startswith("docs/") and p.suffix.lower() in {".md", ".rst", ".txt", ".png", ".jpg", ".jpeg", ".svg"} + + +def unsafe_documentation(ref, paths): + entries = subprocess.check_output(["git", "ls-tree", "-rz", "--full-tree", ref]).split(b"\0") + for entry in entries: + if not entry: + continue + metadata, name = entry.split(b"\t", 1) + path = name.decode("utf-8", "surrogateescape") + if path in paths and documentation(path) and metadata.split(b" ", 1)[0] != b"100644": + return True + return False + + +def select(project, paths): + selected = set() + for path in paths: + if documentation(path): + continue + if project == "server" and (Path(path).name == "pom.xml" or path.startswith("install-dist/")): + selected.add("dependency_license") + if path.startswith(".github/workflows/") and Path(path).name in WORKFLOWS[project]: + selected.update(WORKFLOWS[project][Path(path).name]) + continue + if path.endswith(".proto"): + return set(MODULES[project]) + if project == "server": + if path.startswith("hugegraph-server/hugegraph-hstore/"): + selected.add("hstore") + continue + if path.startswith("hugegraph-server/hugegraph-dist/"): + selected.update(["server", "pd", "store", "hstore", "docker", "cluster"]) + continue + if path.startswith(("hugegraph-server/hugegraph-core/", "hugegraph-server/hugegraph-api/", Review Comment: Important: Server paths outside core/api/test/dist do not select the PD/Store/HStore suite, so two checks that read those files never run. `select("server", ["hugegraph-server/pom.xml"])` and `select("server", ["hugegraph-server/hugegraph-rocksdb/pom.xml"])` both return {server, cluster, dependency_license}, so `pd_store` is skipped. But `hugegraph-server/hugegraph-hstore/pom.xml` uses `hugegraph-server/pom.xml` as its parent, and `pd_store / rocksdb-compatibility` (rocksdb-compatibility/run.sh line 49) compares the effective rocksdbjni version of `hugegraph-server/hugegraph-rocksdb`. A server-side RocksDB override or a parent-pom dependency change passes the gate without either check. On master, pd-store-ci ran for `hugegraph-server/**`. Please add `hstore` for `hugegraph-server/pom.xml` and `hugegraph-server/hugegraph-rocksdb/`, or move the compatibility job into the server suite. ########## .github/workflows/server-ci.yml: ########## @@ -223,51 +270,133 @@ jobs: disable_search: true fail_ci_if_error: false + server-rocksdb: + name: server_rocksdb (Java ${{ matrix.JAVA_VERSION }}) + needs: [plan, java-runtime] + if: needs.plan.outputs.server == 'true' + runs-on: ubuntu-24.04 + env: *linux-server-env + strategy: + fail-fast: false + matrix: + BACKEND: [ rocksdb ] + JAVA_VERSION: ${{ fromJSON(needs.java-runtime.outputs.versions || '["unavailable"]') }} + steps: *linux-server-steps + + commons: + name: commons + needs: plan + if: needs.plan.outputs.commons == 'true' + uses: ./.github/workflows/commons-ci.yml + secrets: inherit + + pd_store: + name: pd_store + needs: plan + if: needs.plan.outputs.pd_store == 'true' + uses: ./.github/workflows/pd-store-ci.yml + secrets: inherit + + cluster: + name: cluster + needs: plan + if: needs.plan.outputs.cluster == 'true' + uses: ./.github/workflows/cluster-test-ci.yml + secrets: inherit + + docker: + name: docker + needs: plan + if: needs.plan.outputs.docker == 'true' + uses: ./.github/workflows/docker-build-ci.yml + secrets: inherit + + helm: + name: helm + needs: plan + if: needs.plan.outputs.helm == 'true' + uses: ./.github/workflows/helm-chart-ci.yml + + dependency_license: Review Comment: Important: `dependency_license` is part of the required `affected-module-tests` gate, so the "3rd-party" check becomes a merge blocker, while docs/ci.md says license checks run independently. Any change to a pom.xml, `install-dist/` or an unknown path selects `dependency_license`, and `gate()` fails when `dependency-review` fails. On master this workflow is not required. The four latest failed "3rd-party" runs on other PRs (for example run 37348245036) stop on "Dependency review detected vulnerable packages", and in this PR's run `dependency_license / dependency-review` failed with "fetch failed", so `affected-module-tests` here will fail as well. Please keep `dependency_license` out of the gate (run it next to `check-license`), or state in docs/ci.md and the PR body that it is now blocking. ########## .github/scripts/ci-policy.py: ########## @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Conservative CI selection and GitHub-verified test receipt reuse.""" + +import argparse +import hashlib +import io +import json +import os +from pathlib import Path +import subprocess +import zipfile +from urllib.parse import urlencode + +MODULES = { + "server": ["server", "commons", "struct", "pd", "store", "hstore", "cluster", "docker", "helm", "dependency_license"], + "toolchain": ["client", "loader", "tools", "spark", "hubble", "go"], +} +PREFIXES = { + "server": {"hugegraph-server/": "server", "hugegraph-commons/": "commons", + "hugegraph-struct/": "struct", "hugegraph-pd/": "pd", "hugegraph-store/": "store", + "hugegraph-cluster-test/": "cluster", "docker/": "docker", "helm/": "helm"}, + "toolchain": {"hugegraph-client/": "client", "hugegraph-client-go/": "go", + "hugegraph-loader/": "loader", "hugegraph-tools/": "tools", + "hugegraph-spark-connector/": "spark", "hugegraph-hubble/": "hubble"}, +} +WORKFLOWS = { + "server": {"server-ci.yml": ["server"], "commons-ci.yml": ["commons"], + "pd-store-ci.yml": ["pd", "store", "hstore"], "cluster-test-ci.yml": ["cluster"], + "docker-build-ci.yml": ["docker"], "helm-chart-ci.yml": ["helm"], + "codeql-analysis.yml": [], "riscv64-ci.yml": ["server"], "check-dependencies.yml": ["dependency_license"]}, + "toolchain": {"client-ci.yml": ["client"], "client-go-ci.yml": ["go"], + "loader-ci.yml": ["loader"], "tools-ci.yml": ["tools"], + "spark-connector-ci.yml": ["spark"], "hubble-ci.yml": ["hubble"], + "codeql-analysis.yml": []}, +} +DEPENDENTS = { + "server": {"commons": ["server", "pd", "store", "hstore", "cluster"], + "struct": ["server", "pd", "store", "hstore", "cluster"], + "server": ["cluster"], "pd": ["store", "hstore", "cluster"], + "store": ["hstore", "cluster"], "hstore": ["cluster"]}, + "toolchain": {"client": ["loader", "tools", "spark", "hubble"], "loader": ["hubble"]}, +} + + +def git(*args): + return subprocess.check_output(["git", *args], text=True).strip() + + +def api(path, binary=False): + result = subprocess.run(["gh", "api", "--method", "GET", path], check=True, capture_output=True, timeout=30) + return result.stdout if binary else json.loads(result.stdout) + + +def documentation(path, mode="100644"): + """Only prose and static documentation assets; never source or config.""" + if mode != "100644": + return False + p = Path(path) + prose_names = {"README.md", "README_CN.md", "README_ZH.md", "AGENTS.md"} + module_roots = {prefix.rstrip("/") for mapping in PREFIXES.values() for prefix in mapping} + module_roots.update("hugegraph-server/" + module for module in [ + "hugegraph-api", "hugegraph-core", "hugegraph-dist", "hugegraph-example", + "hugegraph-hbase", "hugegraph-hstore", "hugegraph-rocksdb", "hugegraph-test"]) + if p.name in prose_names and (str(p.parent) == "." or str(p.parent) in module_roots): + return True + return path.startswith("docs/") and p.suffix.lower() in {".md", ".rst", ".txt", ".png", ".jpg", ".jpeg", ".svg"} + + +def unsafe_documentation(ref, paths): + entries = subprocess.check_output(["git", "ls-tree", "-rz", "--full-tree", ref]).split(b"\0") + for entry in entries: + if not entry: + continue + metadata, name = entry.split(b"\t", 1) + path = name.decode("utf-8", "surrogateescape") + if path in paths and documentation(path) and metadata.split(b" ", 1)[0] != b"100644": + return True + return False + + +def select(project, paths): + selected = set() + for path in paths: + if documentation(path): + continue + if project == "server" and (Path(path).name == "pom.xml" or path.startswith("install-dist/")): + selected.add("dependency_license") + if path.startswith(".github/workflows/") and Path(path).name in WORKFLOWS[project]: + selected.update(WORKFLOWS[project][Path(path).name]) + continue + if path.endswith(".proto"): + return set(MODULES[project]) + if project == "server": + if path.startswith("hugegraph-server/hugegraph-hstore/"): + selected.add("hstore") + continue + if path.startswith("hugegraph-server/hugegraph-dist/"): + selected.update(["server", "pd", "store", "hstore", "docker", "cluster"]) + continue + if path.startswith(("hugegraph-server/hugegraph-core/", "hugegraph-server/hugegraph-api/", + "hugegraph-server/hugegraph-test/")): + selected.update(["server", "hstore"]) + continue + module = next((value for prefix, value in PREFIXES[project].items() if path.startswith(prefix)), None) + if module is None or path.endswith(".proto"): + return set(MODULES[project]) + selected.add(module) + if project == "server" and ("Dockerfile" in Path(path).name or "docker-entrypoint" in path): + selected.add("docker") + changed = True + while changed: + before = set(selected) + for module in before: + selected.update(DEPENDENTS[project].get(module, [])) + changed = before != selected + return selected + + +def fingerprint(ref, policy=False): + """Hash blob identities, including paths; exclude only the strict prose whitelist.""" + entries = subprocess.check_output(["git", "ls-tree", "-rz", "--full-tree", ref]).split(b"\0") + digest = hashlib.sha256() + for entry in sorted(entries, key=lambda e: e.split(b"\t", 1)[-1]): + if not entry: + continue + metadata, name = entry.split(b"\t", 1) + path = name.decode("utf-8", "surrogateescape") + if policy: + if not (path.startswith(".github/") or path == ".asf.yaml"): + continue + elif documentation(path, metadata.split(b" ", 1)[0].decode()): + continue + digest.update(metadata + b"\t" + name + b"\0") + return digest.hexdigest() + + +def remote_fingerprint(repository, sha, policy_only=False, fetch=api): + tree = fetch(f"repos/{repository}/git/trees/{sha}?recursive=1") + if tree.get("truncated"): + raise ValueError("truncated proof tree") + digest = hashlib.sha256() + for entry in sorted(tree["tree"], key=lambda item: item["path"].encode()): + path = entry["path"] + if entry["type"] == "tree": + continue + if policy_only: + if not (path.startswith(".github/") or path == ".asf.yaml"): + continue + elif documentation(path, entry["mode"]): + continue + digest.update((entry["mode"] + " " + entry["type"] + " " + entry["sha"] + + "\t" + path + "\0").encode()) + return digest.hexdigest() + + +def proof_pr(plan, run, fetch): + associations = run.get("pull_requests", []) + if any(pr.get("number") == plan["pr"] for pr in associations): + return True + owner = run.get("head_repository", {}).get("owner", {}).get("login") + branch = run.get("head_branch") + if not owner or not branch: + return False + candidates = pages(f"repos/{plan['repository']}/pulls?" + urlencode({ + "state": "open", "head": f"{owner}:{branch}"}), fetch) + return any(pr.get("number") == plan["pr"] + and pr.get("base", {}).get("repo", {}).get("full_name") == plan["repository"] + and pr.get("head", {}).get("ref") == branch + and pr.get("head", {}).get("repo", {}).get("full_name") == plan["source"] + for pr in candidates) + + +def suites(project, selected): + if project == "toolchain": + return sorted(selected) + result = [] + if "server" in selected: + result.extend(["server_memory", "server_rocksdb"]) + for module in ["commons", "cluster", "docker", "helm", "dependency_license"]: + if module in selected: + result.append(module) + if selected.intersection({"pd", "store", "hstore", "struct"}): + result.append("pd_store") + return sorted(result) + + +def pages(path, fetch=api): + result = [] + for page in range(1, 11): + value = fetch(path + ("&" if "?" in path else "?") + urlencode({"per_page": 100, "page": page})) + batch = value["jobs"] if isinstance(value, dict) else value + result.extend(batch) + if len(batch) < 100: + return result + raise ValueError("API pagination exceeded verification bound") + + +def successful_jobs(repository, run_id, suite, fetch=api): + jobs = pages(f"repos/{repository}/actions/runs/{run_id}/jobs", fetch) + matching = [job for job in jobs if job.get("name") == suite or job.get("name", "").startswith((suite + " / ", suite + " ("))] + if not matching or any(job.get("conclusion") != "success" for job in matching): + raise ValueError("missing or unsuccessful suite jobs") + return sorted(job["id"] for job in matching) + + +def validate_receipt(plan, receipt, fetch=api): + for key in ["schema", "repository", "project", "pr", "source", "branch", "base", "inputFingerprint", "policyFingerprint"]: + if receipt.get(key) != plan.get(key): + raise ValueError("receipt provenance differs: " + key) + proof = receipt.get("proofs", {}) + required = plan["expected"] + if not required or not set(required).issubset(proof): + raise ValueError("receipt lacks selected suites") + verified = {} + for suite in required: + item = proof[suite] + run = fetch(f"repos/{plan['repository']}/actions/runs/{int(item['runID'])}") + if (run.get("status") != "completed" + or run.get("event") != "pull_request" or run.get("head_sha") != item.get("head") + or run.get("workflow_id") != plan["workflowID"] + or run.get("head_repository", {}).get("full_name") != plan["source"] + or run.get("head_branch") != plan["branch"]): + raise ValueError("proof run is not a successful trusted workflow") + successful_jobs(plan["repository"], item["runID"], "affected-module-tests", fetch) + if not proof_pr(plan, run, fetch): + raise ValueError("proof run lacks matching PR association") + merge = fetch(f"repos/{plan['repository']}/git/commits/{item['testedMergeSHA']}") + if [parent["sha"] for parent in merge.get("parents", [])] != [plan["base"], item["head"]]: + raise ValueError("tested merge parents differ") + actual_input = remote_fingerprint(plan["repository"], item["testedMergeSHA"], fetch=fetch) + if plan["project"] == "toolchain": + context = json.dumps(plan.get("externalInputs", {}), sort_keys=True, separators=(",", ":")) + actual_input = hashlib.sha256((actual_input + context).encode()).hexdigest() + if (actual_input != plan["inputFingerprint"] or remote_fingerprint( + plan["repository"], item["testedMergeSHA"], policy_only=True, fetch=fetch) + != plan["policyFingerprint"]): + raise ValueError("actual tested inputs differ from claimed receipt") + ids = successful_jobs(plan["repository"], item["runID"], suite, fetch) + if ids != item.get("jobIDs"): + raise ValueError("actual job evidence differs") + verified[suite] = item + return verified + + +def find_reuse(plan, fetch=api): + """Receipts are uploaded by this workflow, not read from the PR tree.""" + repository = plan["repository"] + current = fetch(f"repos/{repository}/actions/runs/{os.environ['GITHUB_RUN_ID']}") + plan["workflowID"] = current["workflow_id"] + runs = fetch(f"repos/{repository}/actions/workflows/{plan['workflowID']}/runs?" + urlencode({ Review Comment: Important: Receipt lookup reads only the 30 newest completed pull_request runs of this workflow across the whole repository, so a docs follow-up misses its own receipt once the tested run leaves that window. The query has no `branch` filter and no pagination. Right now the 30 newest completed PR runs of this workflow (id 92515655) span 2026-10-04 18:36 to 2026-10-05 17:24 UTC across 10 branches, 14 of them cancelled. A docs commit pushed about a day after the tested code push finds no receipt and reruns every selected suite, which is the case reuse is meant to save. Please add `branch=plan["branch"]` to the query (the loop already checks the head repository) and page further back with a fixed bound, as `pages()` does for jobs. ########## .github/scripts/ci-policy.py: ########## @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Conservative CI selection and GitHub-verified test receipt reuse.""" + +import argparse +import hashlib +import io +import json +import os +from pathlib import Path +import subprocess +import zipfile +from urllib.parse import urlencode + +MODULES = { + "server": ["server", "commons", "struct", "pd", "store", "hstore", "cluster", "docker", "helm", "dependency_license"], + "toolchain": ["client", "loader", "tools", "spark", "hubble", "go"], +} +PREFIXES = { + "server": {"hugegraph-server/": "server", "hugegraph-commons/": "commons", + "hugegraph-struct/": "struct", "hugegraph-pd/": "pd", "hugegraph-store/": "store", + "hugegraph-cluster-test/": "cluster", "docker/": "docker", "helm/": "helm"}, Review Comment: Important: Changes under `docker/` select only the `docker` suite, but the Compose tests for those files run only in `server_rocksdb`. `select("server", ["docker/test-compose.sh"])` and `docker/docker-compose.yml` both return {docker}. `docker/test-compose.sh render` and `smoke` are called only from the RocksDB lane in server-ci.yml ("Validate Docker integration", "Run Compose auth-on smoke tests"); docker-build-ci.yml never calls them. A Compose change now merges with its own tests skipped, while master ran them on every PR. The same applies to `hugegraph-store/hg-store-dist/src/assembly/static/bin/util.sh`, which inside the gate only the RocksDB lane's check_port test covers. Please also select `server` for `docker/` (at least the compose files, `conf/` and `test-compose.sh`) and for that store `util.sh`, or move these steps into the docker suite. ########## .github/scripts/ci-policy.py: ########## @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Conservative CI selection and GitHub-verified test receipt reuse.""" + +import argparse +import hashlib +import io +import json +import os +from pathlib import Path +import subprocess +import zipfile +from urllib.parse import urlencode + +MODULES = { + "server": ["server", "commons", "struct", "pd", "store", "hstore", "cluster", "docker", "helm", "dependency_license"], + "toolchain": ["client", "loader", "tools", "spark", "hubble", "go"], +} +PREFIXES = { + "server": {"hugegraph-server/": "server", "hugegraph-commons/": "commons", + "hugegraph-struct/": "struct", "hugegraph-pd/": "pd", "hugegraph-store/": "store", + "hugegraph-cluster-test/": "cluster", "docker/": "docker", "helm/": "helm"}, + "toolchain": {"hugegraph-client/": "client", "hugegraph-client-go/": "go", + "hugegraph-loader/": "loader", "hugegraph-tools/": "tools", + "hugegraph-spark-connector/": "spark", "hugegraph-hubble/": "hubble"}, +} +WORKFLOWS = { + "server": {"server-ci.yml": ["server"], "commons-ci.yml": ["commons"], Review Comment: Minor: `server-ci.yml` maps only to `server`, but this file now holds the plan, the gate and the calls for every suite. A PR that edits only the `pd_store`, `commons` or `docker` job in server-ci.yml selects server and cluster and skips the edited call. A wrong `if:`, `with:` or `secrets:` change then merges green and fails the next unrelated PR that selects that suite. Please map `server-ci.yml` to all server modules. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
