Kiểm tra tương thích Grafana so từ phiên bản tối thiểu đã khai báo

Job kiểm tra API của Sensor Floor Map đỏ 12 lần liền sau khi Grafana 13.3.0 ra mắt. Nâng package không đủ, sửa một dòng trong plugin.json mới hết.

Phan Minh Đăng Khoa
4 phút đọcAI viết · AI soát
Mục lục

Sensor Floor Map là plugin panel Grafana mã nguồn mở trong bài về ký số bản phát hành. Từ 1/11 đến 4/11/2026, job “Latest Grafana API compatibility check” của plugin đỏ 12 lần, trên tám pull request từ #30 đến #37. PR #38 làm job xanh lại vào ngày 4/11 mà không tắt bài kiểm tra.

Job này chạy gì

Workflow build plugin, rồi gọi action is-compatible của Grafana trên file src/module.ts:

# .github/workflows/is-compatible.yml
- name: Compatibility check
  uses: grafana/plugin-actions/is-compatible@is-compatible/v1.1.0
  with:
    module: ${{ steps.find-module-ts.outputs.modulets }}
    comment-pr: 'no'
    fail-if-incompatible: 'yes'

Action này chạy npx @grafana/levitate@latest is-compatible. Levitate tìm các API Grafana mà module.ts gọi, rồi so chúng giữa hai phiên bản package Grafana. Kết quả có cụm “not fully compatible” thì job đỏ.

Grafana 13.3.0 đổi đúng một chữ ký hàm

Theo npm, @grafana/data 13.3.0 lên ngày 27/10. Lần chạy xanh cuối cùng của job là ngày 26/10. Lần chạy kế tiếp, ngày 1/11, báo lỗi:

Comparing @grafana/[email protected] to @grafana/[email protected]
1) Changed `PanelPlugin.useFieldConfig` used in `src/module.ts:169`
-useFieldConfig(config?: SetFieldConfigOptionsArgs<TFieldConfigOptions>): this;
+useFieldConfig(config?: SetFieldConfigOptionsArgs<TFieldConfigOptions, TOptions>): this;

Tham số kiểu thứ hai dùng để gán kiểu cho context.options trong editor của field config. Mặc định nó là unknown. Phần thân hàm thì giữ nguyên. Đoạn useFieldConfig đã biên dịch trong PanelPlugin.mjs giống hệt nhau ở 13.2.4 và 13.3.0:

useFieldConfig(config = {}) {
  this._initConfigRegistry = () => createFieldConfigRegistry(config, this.meta.name);
  return this;
}

Plugin chạy trên hai bản như nhau. Levitate vẫn báo chữ ký đổi, và job coi mọi báo cáo là lỗi.

Con số 13.2.0 ở đâu ra

Ngày 1/11 có hai bản action cùng chạy với một bản Grafana mới. Mỗi bản so từ một mốc khác nhau.

Lần chạy đầu trên PR #31, #32 và #33 dùng action 1.0.4. Chúng so @grafana/[email protected], bản đang cài, với 13.3.0. Với 1.0.4, nâng package lên 13.3.0 là đủ để hết lỗi.

PR #30 của Dependabot nâng action lên 1.1.0 và merge cùng ngày. Bản 1.1.0 thêm một bước trước khi gọi levitate:

# grafana/plugin-actions, is-compatible/action.yml at is-compatible/v1.1.0
PLUGIN_JSON="$(dirname "$LEVITATE_PATH")/plugin.json"
GRAFANA_DEP=$(jq -r '.dependencies.grafanaDependency // ""' "$PLUGIN_JSON")
MIN_PACKAGE_VERSION=$(echo "$GRAFANA_DEP" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)

Phiên bản đầu tiên trong grafanaDependency được truyền cho levitate qua --min-package-version. Plugin khai báo >=13.2.0, nên mốc so là 13.2.0, bất kể package.json cài bản nào. PR #38 có ghi lại một lần chạy thử trên máy: mọi package @grafana/* đã lên 13.3.0, mức tối thiểu vẫn để 13.2.0. Levitate báo đúng thay đổi cũ.

Cách sửa: khai báo 13.3 là bản tối thiểu

PR #38 sửa một dòng trong src/plugin.json:

-    "grafanaDependency": ">=13.2.0",
+    "grafanaDependency": ">=13.3.0",

Năm package runtime của Grafana lên 13.3.0 cùng lúc, ghim đúng phiên bản. Server Docker chạy local giờ mặc định dùng Grafana 13.3.0. Bản mặc định của scaffold là 13.2.4, thấp hơn mức tối thiểu mới nên sẽ không nạp được plugin. Ngay trên PR, job in ra Detected minimum Grafana version: 13.3.0 và appears to be compatible.

Cái giá là bỏ hỗ trợ Grafana 13.2. Ma trận test end-to-end lấy từ grafanaDependency, nên bản 13.2.5 không còn được chạy. Bản phát hành mới nhất, 0.2.2, vẫn khai báo >=13.2.0. Người dùng chỉ gặp mức tối thiểu mới ở bản phát hành sau.

Một test giữ ba con số khớp nhau

Mức tối thiểu khai báo, phiên bản package ghim và phiên bản server local nằm ở ba file khác nhau. src/grafanaVersion.test.ts kiểm tra ba chỗ này khớp nhau. Đây là một trong ba test:

// src/grafanaVersion.test.ts
const min = semver.minVersion(grafanaDependency);
const built = semver.parse(dependencies['@grafana/data']);
expect(`${min!.major}.${min!.minor}`).toBe(`${built!.major}.${built!.minor}`);

Hai test còn lại kiểm tra năm package dùng chung một phiên bản, và bản Docker mặc định thoả grafanaDependency. Trong các lần thử đột biến của PR, trả mức tối thiểu về >=13.2.0 làm test này đỏ. Bỏ phần ghi đè trong Docker Compose làm test server đỏ.

Bảy lần merge khi job đang đỏ

PR #30 đến #36 đều merge ngày 1/11 trong lúc job này đỏ. Job này không phải check bắt buộc, nên đỏ cũng không chặn gì. Cả 12 lần chạy lỗi đều báo cùng một thay đổi duy nhất là useFieldConfig. Không lần nào do code của PR đang chạy. Job đỏ đến khi PR #38 merge ngày 4/11.

Bài học

  • Từ is-compatible 1.1.0, bài kiểm tra so từ phiên bản đầu tiên trong grafanaDependency, không phải từ lockfile.
  • Một bản Grafana mới có thể làm mọi PR đang mở đỏ dù PR không đổi gì liên quan.
  • Thay đổi chỉ ở kiểu dữ liệu vẫn làm job đỏ. Ở đây, nâng mức tối thiểu khai báo là cách duy nhất vừa sửa lỗi vừa giữ bài kiểm tra.
  • Đặt mức tối thiểu khai báo, phiên bản package ghim và phiên bản server local dưới cùng một unit test.
  • Check không bắt buộc thì dễ bị merge vượt qua. Đọc log đỏ đầu tiên trước lần merge kế tiếp.
Phan Minh Đăng Khoa
Principal Engineer · AI, IoT và tự động hoá công nghiệp.
← Bài trướcWorkflow release chạy xanh mà plugin vẫn chưa được ký