fix(ci): 修 flutter analyze 闸长期 exit 1(形同虚设)
发现:CI flutter analyze 退出码 1(1204 个 info,0 error/warning),其中 1191 来自 第三方 vendored 包 lucide_icons_patched —— 这道闸一直红/无效。 - analysis_options.yaml:exclude packages/lucide_icons_patched/**(去 1191 噪音) - ci.yml:flutter analyze --no-fatal-infos(info 是建议级不该硬挡 merge; error/warning 仍致命)→ analyze EXIT 0、闸真正可用 - 顺手清 11 个 clean 文件 info:auth_api 删 >>>AUTHLOG 调试 print 残留(+unused sw)、 account_page/plan_card withOpacity→withValues、vpn_bridge where(is Map)→whereType、 测试文件删多余 import + final→const - 剩 2 个 info 在 stats-overhaul dirty 文件(stats_page/device_stat_row),留其合并清 - 验证:flutter analyze --no-fatal-infos EXIT 0(1204→2)、flutter test 48 全过 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -77,7 +77,7 @@ jobs:
|
||||
docker run --rm \
|
||||
-v "$PWD/client:/app" -w /app \
|
||||
ghcr.io/cirruslabs/flutter:stable \
|
||||
bash -c "flutter pub get && flutter analyze && flutter test test/unit test/widget test/contract"
|
||||
bash -c "flutter pub get && flutter analyze --no-fatal-infos && flutter test test/unit test/widget test/contract"
|
||||
|
||||
# ── Job 5: Portable SQL Scan (支柱 3:双库可移植)─────────────────────────
|
||||
# server Go 运行时查询不得含 MySQL 专属构造(同一份 SQL 要跑 mysql 与 sqlite)。
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
analyzer:
|
||||
# 第三方 vendored path 依赖不该被项目 lint 评判(否则 ~1191 条 unnecessary_const
|
||||
# 噪音淹没自身 issue,让 analyze 闸形同虚设)。
|
||||
exclude:
|
||||
- packages/lucide_icons_patched/**
|
||||
|
||||
linter:
|
||||
rules:
|
||||
prefer_const_constructors: false
|
||||
|
||||
@@ -110,9 +110,9 @@ class VpnStatsEvent {
|
||||
uploadSpeed: (m['uploadSpeed'] as num?)?.toDouble() ?? 0.0,
|
||||
downloadSpeed: (m['downloadSpeed'] as num?)?.toDouble() ?? 0.0,
|
||||
urltestResults: ((m['urltestResults'] as List?)
|
||||
?.where((e) => e is Map)
|
||||
?.whereType<Map>()
|
||||
.map((e) => UrltestResult.fromMap(
|
||||
Map<String, dynamic>.from(e as Map),
|
||||
Map<String, dynamic>.from(e),
|
||||
))
|
||||
.toList()) ??
|
||||
const [],
|
||||
|
||||
@@ -179,7 +179,7 @@ class _PlanBanner extends StatelessWidget {
|
||||
child: Row(children: [
|
||||
Container(
|
||||
width: 44, height: 44,
|
||||
decoration: BoxDecoration(color: PangolinColors.white.withOpacity(0.18), shape: BoxShape.circle),
|
||||
decoration: BoxDecoration(color: PangolinColors.white.withValues(alpha: 0.18), shape: BoxShape.circle),
|
||||
child: const Icon(PangolinIcons.crown, size: 22, color: PangolinColors.white),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -187,7 +187,7 @@ class _PlanBanner extends StatelessWidget {
|
||||
Text(email, style: const TextStyle(color: PangolinColors.white, fontWeight: FontWeight.w700, fontSize: 16)),
|
||||
const SizedBox(height: 4),
|
||||
Text(expiresLabel.isEmpty ? t.proMember : '${t.proMember} · $expiresLabel',
|
||||
style: TextStyle(color: PangolinColors.white.withOpacity(0.85), fontSize: 12)),
|
||||
style: TextStyle(color: PangolinColors.white.withValues(alpha: 0.85), fontSize: 12)),
|
||||
])),
|
||||
FilledButton(
|
||||
onPressed: onUpgrade,
|
||||
|
||||
@@ -99,8 +99,6 @@ class AuthApi {
|
||||
|
||||
Future<http.Response> _post(String path, Map<String, dynamic> body) async {
|
||||
final uri = Uri.parse('$baseUrl$path');
|
||||
print('>>>AUTHLOG POST $uri (baseUrl=$baseUrl) 发起...');
|
||||
final sw = Stopwatch()..start();
|
||||
try {
|
||||
final resp = await _client
|
||||
.post(
|
||||
@@ -109,10 +107,8 @@ class AuthApi {
|
||||
body: jsonEncode(body),
|
||||
)
|
||||
.timeout(const Duration(seconds: 15));
|
||||
print('>>>AUTHLOG POST $uri -> HTTP ${resp.statusCode} (${sw.elapsedMilliseconds}ms)');
|
||||
return resp;
|
||||
} on Exception catch (e) {
|
||||
print('>>>AUTHLOG POST $uri 失败 (${sw.elapsedMilliseconds}ms): ${e.runtimeType}: $e');
|
||||
throw AuthApiException(
|
||||
statusCode: -1,
|
||||
messageZh: '网络请求失败,请检查连接后重试',
|
||||
|
||||
@@ -27,7 +27,7 @@ class PlanCard extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final c = context.pangolin;
|
||||
final onCard = featured ? PangolinColors.white : c.fg1;
|
||||
final subColor = featured ? PangolinColors.white.withOpacity(0.92) : c.fg2;
|
||||
final subColor = featured ? PangolinColors.white.withValues(alpha: 0.92) : c.fg2;
|
||||
|
||||
final card = Container(
|
||||
padding: const EdgeInsets.fromLTRB(20, 22, 20, 20),
|
||||
@@ -44,7 +44,7 @@ class PlanCard extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(name, style: PangolinText.sm.copyWith(color: featured ? PangolinColors.white.withOpacity(0.85) : c.fg2, fontWeight: FontWeight.w600)),
|
||||
Text(name, style: PangolinText.sm.copyWith(color: featured ? PangolinColors.white.withValues(alpha: 0.85) : c.fg2, fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// 4. selectOutbound 切换时产生 connecting → on 重连序列
|
||||
// 5. getStatus / getActiveOutbound / setKillSwitch 返回正确值
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:pangolin_vpn/bridge/vpn_bridge.dart';
|
||||
import 'package:pangolin_vpn/bridge/vpn_bridge_mock.dart';
|
||||
@@ -225,7 +224,7 @@ void main() {
|
||||
// ── 5. VpnStatsEvent schema round-trip ───────────────────────
|
||||
group('VpnStatsEvent schema', () {
|
||||
test('fromMap / toMap round-trip', () {
|
||||
final original = const VpnStatsEvent(
|
||||
const original = VpnStatsEvent(
|
||||
uploadBytes: 1024,
|
||||
downloadBytes: 4096,
|
||||
uploadSpeed: 512.0,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// 让 widget/golden 测试用真字体渲染、且不触发 google_fonts 运行时拉取(避免抛异常)。
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
Reference in New Issue
Block a user