This is an automated email from the ASF dual-hosted git repository.

ethanfeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new 9a689b748 [CELEBORN-2028] Setup GA for grafana dashboard
9a689b748 is described below

commit 9a689b74825d6a009a603f677a151c60d68fc4ac
Author: Wang, Fei <[email protected]>
AuthorDate: Tue Jun 10 16:14:49 2025 +0800

    [CELEBORN-2028] Setup GA for grafana dashboard
    
    ### What changes were proposed in this pull request?
    
    Setup the GA for grafana dashboard.
    
    1. Lint the dashboard with https://github.com/grafana/dashboard-linter
    2. Check the duplicate id in dashboard json file
    
    ### Why are the changes needed?
    
    It is helpful for grafana related PR review, for example: 
https://github.com/apache/celeborn/pull/3307#discussion_r2134799722
    
    ### Does this PR introduce _any_ user-facing change?
    No.
    
    ### How was this patch tested?
    GA.
    
    <img width="1407" alt="image" 
src="https://github.com/user-attachments/assets/35452633-ddff-4140-b929-3c44a943a2ab";
 />
    
    Closes #3316 from turboFei/dashboard.
    
    Authored-by: Wang, Fei <[email protected]>
    Signed-off-by: mingji <[email protected]>
---
 .github/workflows/grafana.yml | 53 +++++++++++++++++++++++++++++++
 assets/grafana/.lint          | 30 ++++++++++++++++++
 dev/lint_grafana.py           | 73 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)

diff --git a/.github/workflows/grafana.yml b/.github/workflows/grafana.yml
new file mode 100644
index 000000000..2632e213e
--- /dev/null
+++ b/.github/workflows/grafana.yml
@@ -0,0 +1,53 @@
+#
+# 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.
+#
+
+name: Grafana Dashboard CI
+
+on:
+  push:
+    branches:
+      - main
+      - branch-*
+  pull_request:
+    branches:
+      - main
+      - branch-*
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+    steps:
+    - uses: actions/checkout@v4
+    - name: Setup Go
+      uses: actions/setup-go@v4
+      with:
+        go-version: 'stable'
+    - uses: actions/setup-python@v5
+      with:
+        python-version: "3.12"
+        check-latest: true
+    # See https://github.com/grafana/dashboard-linter
+    - name: Install dashboard-linter
+      run: go install github.com/grafana/dashboard-linter@latest
+    - name: Lint Celeborn Dashboards
+      run: |
+        for dashboard in assets/grafana/*.json; do
+          python3 dev/lint_grafana.py "$dashboard"
+          dashboard-linter lint "$dashboard" --config assets/grafana/.lint 
--strict
+        done
diff --git a/assets/grafana/.lint b/assets/grafana/.lint
new file mode 100644
index 000000000..6f86a8bd5
--- /dev/null
+++ b/assets/grafana/.lint
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+# See 
https://github.com/grafana/dashboard-linter/blob/main/docs/index.md#exclusions-and-warnings
+
+exclusions:
+  template-datasource-rule:
+    reason: Celeborn uses ${DS_PROMETHEUS} variable in the template, which is 
not supported by the rule.
+  panel-datasource-rule:
+    reason: Celeborn uses ${DS_PROMETHEUS} variable in the template, which is 
not supported by the rule.
+  panel-title-description-rule:
+    reason: Some panels have a title but no description.
+  template-on-time-change-reload-rule:
+    reason: Allow dashboard variables not to reload on time change.
+  uneditable-dashboard:
+    reason: Celeborn dashboards are editable.
diff --git a/dev/lint_grafana.py b/dev/lint_grafana.py
new file mode 100755
index 000000000..55a21d97a
--- /dev/null
+++ b/dev/lint_grafana.py
@@ -0,0 +1,73 @@
+#!/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.
+#
+
+import json
+import sys
+from collections import Counter
+
+def traverse_ids(obj, ids):
+    if isinstance(obj, dict):
+        for key, value in obj.items():
+            if key == "id":
+                ids.append(value)
+            traverse_ids(value, ids)
+    elif isinstance(obj, list):
+        for item in obj:
+            traverse_ids(item, ids)
+
+def check_ids(file_path):
+    with open(file_path, "r", encoding="utf-8") as f:
+        data = json.load(f)
+    ids = []
+    traverse_ids(data, ids)
+
+    # Find duplicates.
+    counts = Counter(ids)
+    duplicates = {k: v for k, v in counts.items() if v > 1}
+
+    # Collect numeric IDs.
+    numeric_ids = []
+    for id_value in ids:
+        try:
+            numeric_ids.append(int(id_value))
+        except (ValueError, TypeError):
+            continue
+
+    # print the current maximum numeric id.
+    if numeric_ids:
+        current_max = max(numeric_ids)
+        print(f"Current max numeric id: {current_max}")
+    else:
+        print("No numeric IDs found; cannot compute max numeric id.")
+
+    if duplicates:
+        print("Found duplicate id(s):")
+        for dup, count in duplicates.items():
+            print(f"  {dup}: {count} times")
+        sys.exit(1)
+    else:
+        print("No duplicate id found.")
+
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        print("Usage: python3 lint_grafana.py <path/to/dashboard.json>")
+        sys.exit(1)
+    file_path = sys.argv[1]
+    print(f"Linting: {file_path}")
+    check_ids(file_path)

Reply via email to