Skip to content

v2.5.0

Choose a tag to compare

@wenjianzhang wenjianzhang released this 27 Aug 11:59
· 254 commits to master since this release
76c9d12

This release carries two breaking changes. Read this section before upgrading.

⚠️ Before you upgrade

1. The core import path changed. Go requires a major version of 2 or above to carry /v2 in the module path, so every
github.com/go-admin-team/go-admin-core becomes github.com/go-admin-team/go-admin-core/v2.
That is 210 imports across 95 files here. Anyone who forked this repository will hit conflicts on the import lines when merging upstream — core ships a codemod, coreupgrade, that rewrites them in one pass. #864

2. You must run migrate. The soft-delete marker changes from a nullable datetime to a non-null millisecond integer. Skip the migration and the server starts, but every login is rejected as an incorrect username or password: the code queries deleted_at = 0 while an older database holds NULL, and NULL = 0 is never true. Logins are not the only casualty — menus and departments become invisible too. #863 #870


  • 🔒 Stop writing the database password into the log. The startup line printed the DSN whole, so every deployment wrote its own credential into its own logs, where a log shipper, a support bundle or a screenshot carries it onward. The host and username stay; only the password is replaced. #880
  • 🐛 Fix logins failing on a fresh MySQL install. A seeded menu's sort exceeded MySQL's tinyint, so the run stopped there with Error 1264 and the soft-delete conversion never ran — leaving deleted_at NULL and the login rejecting a password that was correct. sqlite ignores the declared width, so the fault appeared only on MySQL. #877
  • 🐛 Fix the soft-delete migration against a real schema: it dropped a column while an index still referred to it, which SQLite refuses, and read rows through a column named id when sys_dept keys on dept_id and sys_user on user_id. #870
  • 🐛 Give the natural keys a constraint the database can keep. username, role_key and dict_type relied on a SELECT COUNT followed by an INSERT, which two concurrent requests both pass. A nullable delete marker cannot take part in a unique index — NULL is not equal to NULL, so the index looks like a constraint and enforces nothing. #863
  • Code generator
    • 🐛 Fix the column-list endpoint. pkg.Assert panics when its condition is false, and the guard read Assert(TableName == "") — so every request carrying a table name was rejected and the empty one was let through. The model layer repeated the inversion. The endpoint had never returned data. #865
    • 🐛 Fix the mysql-only guard, which was written Assert(true, ...) and never fired. On postgres or sqlserver it returned an empty list with a nil error, or dereferenced a zero-value *gorm.DB. #865
    • 🐛 Fix the table list coming back empty. sys_columns and sys_tables were left out of the soft-delete conversion, so they were queried with deleted_at = 0 against a nullable datetime and every row was invisible. #877
    • 🐛 Fix the candidate table query assuming one database. It named the schema by hand, failing outright when generating from another, and read past the soft delete — so deleting a generator entry never handed its table back. #865
  • File upload
    • 🐛 Fix the panic on source=2 and source=3. Both branches built a zero-value client and called upload on it, asserting a nil Client field. #875
    • 🐛 Fix the qiniu branch uploading to aliyun: qiniuUpload constructed ALiYunOSS, so source=3 could not have reached qiniu even with credentials. #875
    • 🐛 Cloud storage had never been wired up: OXS.Setup is the initialisation path and nothing called it, and no configuration field existed. Credentials now come from extend.fileStore, and an unconfigured provider says so instead of crashing. #875
    • 🐛 Fix Huawei OBS reporting success on a failed upload — the error was printed and nil returned. #875
  • 🐛 Report an unknown database driver instead of panicking. opens[driver] handed gorm.Open a nil function to call, so the operator saw a nil dereference inside gorm with nothing naming the driver — sqlite3 especially, since it needs cgo and only compiles in under the sqlite3 build tag. #865
  • 👌 Stop looking up the data scope on every request. The EnableDP check lived in the scope rather than the middleware, so with data permission switched off — the shipped default — every list, detail, update and delete still paid for a sys_user join whose result was discarded. deptid also joins the token, so all four values the scope is decided by can now be read from it. #876
  • 🔧 Deploys run migrations first and roll back when the new version does not come up. Previously docker rm -f then docker run, with no migration and no health check: a container that exited immediately left the site down with a green deploy. Healthy requires both an HTTP response and a database connection — the captcha endpoint answers without touching the database, so HTTP alone would call a container healthy that cannot reach MySQL. #880
  • 🔧 Make migration output legible. An applied migration printed a bare 1, so seven of them wrote seven lines of 1, and a failure named the error but never the migration. #880
  • 📝 Repoint the README links that stopped resolving: the documentation tutorials, the archived jwt-go repository, and an external link that no longer answers. #867
  • 🔧 Remove the repository mirrors and the leftover Dockerfilebak. #868 #873

本次发布带两处破坏性变更,升级前请先读这一节。

⚠️ 升级必读

1. core 的导入路径变了。 Go 要求主版本 ≥2 必须把 /v2 写进模块路径,所以
github.com/go-admin-team/go-admin-core 全部变成 github.com/go-admin-team/go-admin-core/v2。
本仓库改了 210 处、95 个文件。fork 过本仓库的人合并上游时会在 import 行大量冲突,
可用 core 自带的 coreupgrade 一次性重写自己项目里的导入。#864

2. 必须执行 migrate。 软删除标记从「可空 datetime」改为「非空毫秒整数」,
不跑迁移会出现能启动、但登录报「账号密码不正确」,因为代码查 deleted_at = 0
而旧库里是 NULL,NULL = 0 恒为假 —— 不只是登录,菜单、部门也会全部查不到。
#863 #870


  • 🔒 数据库密码不再写进日志。启动那行日志此前打印完整 DSN,等于每个部署都把自己的数据库凭证写进自己的日志里,日志采集、故障包、终端截图都会把它带走。现在只保留 host 和用户名。#880
  • 🐛 修复 MySQL 全新安装无法登录。种子菜单的 sort 值超出 MySQL 的 tinyint 范围,迁移在这里以 Error 1264 中断,后面的软删除转换从未执行,于是 deleted_at 停在 NULL,登录报「账号密码不正确」而密码其实是对的。sqlite 忽略列宽,所以这个故障只在 MySQL 上出现。#877
  • 🐛 修复软删除迁移在真实表结构上跑不完。删列前未先删依赖索引(SQLite 直接拒绝),且读取行时把主键写死成 id(sys_dept 是 dept_id、sys_user 是 user_id)。#870
  • 🐛 自然键补上数据库层的唯一约束。username / role_key / dict_type 此前只靠「先 COUNT 再 INSERT」保证唯一,并发下两个请求都能通过。可空的删除标记进不了唯一索引 —— NULL 不等于 NULL,索引看着像约束、实际不约束任何东西。#863
  • 代码生成器
    • 🐛 修复取字段列表的接口。pkg.Assert 是条件为假时 panic,而守卫写成了 Assert(TableName == ""),于是带表名的请求全部 500,不带表名的反而放行;模型层还有一处方向相同的反向判断。这个接口从未返回过数据。#865
    • 🐛 修复「只支持 MySQL」的守卫从未生效。写成了 Assert(true, ...),是个空操作。postgres / sqlserver 上不会报错,而是返回空列表加 nil error,或者在零值 *gorm.DB 上崩溃。#865
    • 🐛 修复表列表为空。sys_columns / sys_tables 漏在软删除转换清单之外,运行时用 deleted_at = 0 去查一个可空 datetime 列,每一行都不可见。#877
    • 🐛 修复候选表查询假设只有一个库。排除清单用手写 schema 名的子查询,从别的 schema 生成时直接失败;而且它绕过软删除,删掉生成器条目后那张表再也回不到候选列表。#865
  • 文件上传
    • 🐛 修复 source=2 / source=3 触发 panic。两个分支都在构造零值客户端就调用上传,而 Client 字段为 nil,类型断言直接崩。#875
    • 🐛 修复七牛分支实际走的是阿里云。qiniuUpload 构造的是 ALiYunOSS,所以 source=3 即使有凭证也到不了七牛。#875
    • 🐛 云存储此前从未接通:初始化入口 OXS.Setup 全仓无人调用,配置里也没有对应字段。现在从 extend.fileStore 读取,未配置的服务商返回明确错误而不是崩溃。#875
    • 🐛 修复华为云 OBS 上传失败却返回成功。错误被打印后 return nil。#875
  • 🐛 数据库 driver 未知时给出可读报错。opens[driver] 取到 nil 函数直接被调用,操作者看到的是 gorm 深处的空指针,没有任何信息指向 driver 名 —— sqlite3 尤其容易踩到,它需要 cgo 且只在 sqlite3 构建标签下编入。#865
  • 👌 数据权限不再每请求查一次库。EnableDP 的判断原本在 scope 里而不在中间件里,所以即使数据权限关闭(默认配置就是关的),每个列表/详情/更新/删除仍要跑一次 sys_user join,查完丢掉。同时 deptid 补进 token,四个判定值现在都能从 token 读到。#876
  • 🔧 部署流程:先跑迁移,起不来则回滚。此前是 docker rm -f 后 docker run,不跑迁移、不做健康检查,容器起不来就是「站点已挂、部署全绿」。健康检查要求 HTTP 与数据库连接同时成立 —— 验证码接口不碰数据库,只看 HTTP 会把连不上库的容器判为健康。#880
  • 🔧 迁移输出可读。已执行的迁移原本打印一个裸的 1,七条迁移就是七行 1;失败时只报错误、不说是哪条迁移。#880
  • 📝 修复 README 中失效的链接:文档站教程链接、已归档的 jwt-go 仓库、无法访问的外链。#867
  • 🔧 移除仓库镜像同步与遗留的 Dockerfilebak。#868 #873