三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

HarmonyOS 7 / API 26 Code Linter 落地实战:规则分级、误报白名单和 CI 阻断一次验清

HarmonyOS 7 / API 26 Code Linter 落地实战:规则分级、误报白名单和 CI 阻断一次验清

Code Linter 不是为了让代码看起来整齐,而是为了把低级问题提前挡在提交前。HarmonyOS 7 / API 26 工程如果多人协作,靠人工 review 去发现空判断、异步未处理、无意义状态更新、调试日志残留,效率很低,也容易漏。

这篇按工程落地来讲:规则怎么分级,误报怎么处理,提交前怎么检查,CI 怎么阻断,最后怎么让修复结果能回归。

版本和执行位置

项目说明
工程目标HarmonyOS 7 / API 26
检查对象ArkTS、配置文件、工程脚本
执行位置本地提交前、CI 构建前、合并前
结果要求错误阻断,警告记录,误报可追踪

Linter 如果只在开发者本地跑,很容易有人漏跑。真正稳定的做法是本地快检加 CI 强制检查。

规则先分级

不要一上来把所有规则都设成阻断。否则误报多了,团队会绕开它。

~~~ts

type RuleLevel = 'error' | 'warn' | 'off'

type LintRule = {

name: string

level: RuleLevel

reason: string

}

const rules: LintRule[] = [

{ name: 'no-floating-promise', level: 'error', reason: '异步结果未处理会造成状态不可控' },

{ name: 'no-debug-log-in-release', level: 'error', reason: 'release 包不能残留调试日志' },

{ name: 'prefer-stable-key', level: 'warn', reason: '列表 key 不稳定容易造成状态错位' },

{ name: 'max-function-lines', level: 'warn', reason: '过长函数需要拆分,但不直接阻断' }

]

~~~

我的原则是:会造成线上风险的规则设 error;影响可维护性的先设 warn。等团队适应后,再逐步提高要求。

案例一:异步任务没有处理失败

下面这种写法很常见:

~~~ts

function onPageShow(): void {

loadRemoteConfig()

refreshList()

}

~~~

看起来没问题,但这两个异步任务如果失败,页面不知道;如果返回太晚,还可能覆盖新状态。Linter 至少要把未处理 Promise 拦出来。

~~~ts

function onPageShowBetter(): void {

void loadRemoteConfig().catch(error => {

console.error('[config]', String(error))

})

void refreshListSafely()

}

async function refreshListSafely(): Promise<void> {

try {

const rows = await requestRows()

applyRows(rows)

} catch (error) {

showListError(String(error))

}

}

~~~

这里不是要求所有异步都 await,而是要求每个异步都有明确去向:等待、捕获、忽略但说明原因。

案例二:release 包残留调试日志

调试日志在开发阶段有用,但 release 包里大量 console 会影响排查,也可能泄露内部信息。

~~~ts

type LintIssue = {

file: string

line: number

rule: string

level: RuleLevel

message: string

}

function checkDebugLog(file: string, content: string): LintIssue[] {

return content.split('

').flatMap((line, index) => {

if (line.includes('console.log(')) {

return [{

file,

line: index + 1,

rule: 'no-debug-log-in-release',

level: 'error',

message: 'release 代码不要保留 console.log'

}]

}

return []

})

}

~~~

实际项目可以接成熟 linter,这里写简化版本只是为了说明规则结果要结构化。结构化以后,CI 才能稳定判断是否阻断。

误报白名单要可追踪

没有白名单,误报会拖慢开发;白名单太随意,又会把门禁掏空。所以我会给白名单加原因和过期时间。

~~~ts

type LintIgnore = {

rule: string

file: string

reason: string

expireAt: string

}

function isIgnored(issue: LintIssue, ignores: LintIgnore[]): boolean {

const today = '2026-08-05'

return ignores.some(item => {

return item.rule === issue.rule &&

item.file === issue.file &&

item.expireAt >= today

})

}

~~~

白名单不是永久免死牌。过期后还要重新评估,不然规则会慢慢失效。

CI 阻断逻辑

CI 只需要一个清楚的判断:有没有 error 级问题。

~~~ts

function assertLintPassed(issues: LintIssue[], ignores: LintIgnore[]): void {

const activeIssues = issues.filter(issue => !isIgnored(issue, ignores))

const errors = activeIssues.filter(issue => issue.level === 'error')

for (const issue of activeIssues) {

console.info('[lint-issue]', issue.level, issue.rule, issue.file + ':' + issue.line, issue.message)

}

if (errors.length > 0) {

throw new Error('lint failed with ' + errors.length + ' error(s)')

}

}

~~~

warn 可以输出报告,但不阻断;error 必须失败。这个边界要固定,否则每次 CI 失败都要靠人解释。

本地验证脚本

先用两段代码模拟检查结果。

~~~ts

function verifyLintGate(): void {

const content = [

'function test() {',

' console.log("debug")',

' loadRemoteConfig()',

'}'

].join('

')

const issues = checkDebugLog('src/main/ets/pages/Index.ets', content)

const ignores: LintIgnore[] = []

assertLintPassed(issues, ignores)

}

~~~

预期结果是 CI 阻断,因为 release 代码里出现 console.log。再加一条未过期白名单,可以验证误报放行逻辑是否生效。

~~~ts

function verifyIgnore(): void {

const issue: LintIssue = {

file: 'src/main/ets/pages/DebugOnly.ets',

line: 10,

rule: 'no-debug-log-in-release',

level: 'error',

message: 'temporary debug page'

}

const ignores: LintIgnore[] = [{

rule: 'no-debug-log-in-release',

file: 'src/main/ets/pages/DebugOnly.ets',

reason: 'only used in internal debug build',

expireAt: '2026-08-30'

}]

console.info('[verify-ignore]', isIgnored(issue, ignores))

}

~~~

落地清单

检查项通过标准
规则分级error/warn/off 有明确原因
异步处理未处理 Promise 不能进主干
release 日志console.log 等调试输出被阻断
白名单有原因、有过期时间
CI 输出能定位到文件、行号、规则名
回归本地脚本能复现阻断和放行

小结

HarmonyOS 7 / API 26 工程接 Code Linter,重点不是把规则一次开满,而是把质量门禁落稳。先分级,再处理误报,再把 error 级问题放进 CI 阻断。这样 review 不用反复纠结低级问题,团队也能把精力放到真正的架构和业务风险上。

← 返回列表