From 864ebeed82cda27ce127f96bce79386b5e594fb3 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Tue, 29 Sep 2026 17:29:16 +0800 Subject: [PATCH] fix: load domestic release notes from new docs (#13943) --- core/app/service/upgrade.go | 93 ++++++++++++++++++++++++++++++++++++- docs/README.zh-Hans.md | 4 +- docs/README.zh-Hant.md | 4 +- 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/core/app/service/upgrade.go b/core/app/service/upgrade.go index b718bd08f..6530337dc 100644 --- a/core/app/service/upgrade.go +++ b/core/app/service/upgrade.go @@ -10,6 +10,7 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/1Panel-dev/1Panel/core/app/dto" "github.com/1Panel-dev/1Panel/core/app/model" @@ -25,6 +26,7 @@ import ( "github.com/1Panel-dev/1Panel/core/utils/req_helper" upgradeUtil "github.com/1Panel-dev/1Panel/core/utils/upgrade" "github.com/1Panel-dev/1Panel/core/utils/xpack" + "golang.org/x/net/html" ) type serviceInfo struct { @@ -299,7 +301,7 @@ func (u *UpgradeService) LoadRelease() ([]dto.ReleasesNotes, error) { docSource, _ := settingRepo.GetValueByKey("DocSource") lang, _ := settingRepo.GetValueByKey("Language") var notes []dto.ReleasesNotes - url := "https://1panel.cn/docs/v2/search/search_index.json" + url := "https://docs.fit2cloud.com/1panel/changelog/" useIntlDocs := false lang = strings.ToLower(strings.TrimSpace(lang)) if docSource == "withByRegion" { @@ -315,6 +317,12 @@ func (u *UpgradeService) LoadRelease() ([]dto.ReleasesNotes, error) { return notes, err } defer resp.Body.Close() + if !useIntlDocs { + if resp.StatusCode != http.StatusOK { + return notes, fmt.Errorf("load release notes failed: HTTP %d", resp.StatusCode) + } + return parseReleaseHTML(resp.Body) + } body, err := io.ReadAll(resp.Body) if err != nil { return notes, err @@ -336,6 +344,89 @@ func (u *UpgradeService) LoadRelease() ([]dto.ReleasesNotes, error) { return notes, nil } +func parseReleaseHTML(reader io.Reader) ([]dto.ReleasesNotes, error) { + doc, err := html.Parse(reader) + if err != nil { + return nil, err + } + var article *html.Node + for node := range doc.Descendants() { + if node.Type == html.ElementNode && node.Data == "article" { + article = node + break + } + } + if article == nil { + return nil, fmt.Errorf("release notes article not found") + } + textContent := func(node *html.Node) string { + var text strings.Builder + for child := range node.Descendants() { + if child.Type == html.TextNode { + text.WriteString(child.Data) + } + } + return strings.TrimSpace(strings.ReplaceAll(text.String(), "\u200b", "")) + } + var notes []dto.ReleasesNotes + for heading := range article.Descendants() { + if heading.Type != html.ElementNode || heading.Data != "h3" { + continue + } + version := textContent(heading) + if !strings.HasPrefix(version, "v") { + continue + } + item := dto.ReleasesNotes{Version: version} + var content strings.Builder + section := "" + for node := heading.NextSibling; node != nil; node = node.NextSibling { + if node.Type != html.ElementNode { + continue + } + if node.Data == "h1" || node.Data == "h2" || node.Data == "h3" { + break + } + if item.CreatedAt == "" { + date := textContent(node) + if _, err := time.Parse("2006年1月2日", date); node.Data != "p" || err != nil { + return nil, fmt.Errorf("release date not found for %s", version) + } + item.CreatedAt = date + continue + } + if node.Data == "p" { + section = textContent(node) + } + for child := range node.Descendants() { + if child.Type != html.ElementNode || child.Data != "li" { + continue + } + switch section { + case "新增功能": + item.NewCount++ + case "功能优化": + item.OptimizationCount++ + case "问题修复": + item.FixCount++ + } + } + if err := html.Render(&content, node); err != nil { + return nil, err + } + } + if item.CreatedAt == "" || content.Len() == 0 { + return nil, fmt.Errorf("release notes content not found for %s", version) + } + item.Content = content.String() + notes = append(notes, item) + } + if len(notes) == 0 { + return nil, fmt.Errorf("release notes versions not found") + } + return notes, nil +} + func analyzeDoc(version, content string) dto.ReleasesNotes { var item dto.ReleasesNotes parts := strings.Split(content, "

") diff --git a/docs/README.zh-Hans.md b/docs/README.zh-Hans.md index 9492cab67..31440a81e 100644 --- a/docs/README.zh-Hans.md +++ b/docs/README.zh-Hans.md @@ -53,11 +53,11 @@ $ bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)" -如果是用于离线环境,推荐使用 [安装包方式](https://1panel.cn/docs/v2/installation/enterprise_installation/) 进行安装部署。 +如果是用于离线环境,推荐使用 [安装包方式](https://docs.fit2cloud.com/1panel/installation/enterprise-installation/) 进行安装部署。 **学习资料** -- [在线文档](https://1panel.cn/docs/) +- [在线文档](https://docs.fit2cloud.com/1panel/) - [社区论坛](https://bbs.fit2cloud.com/c/1p/7) ## 版本对比 diff --git a/docs/README.zh-Hant.md b/docs/README.zh-Hant.md index 15b9431c0..cf625b878 100644 --- a/docs/README.zh-Hant.md +++ b/docs/README.zh-Hant.md @@ -55,11 +55,11 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh ``` -如果是用於離線環境,推薦使用 [安裝包方式](https://1panel.cn/docs/installation/package_installation/) 進行安裝部署。 +如果是用於離線環境,推薦使用 [安裝包方式](https://docs.fit2cloud.com/1panel/installation/enterprise-installation/) 進行安裝部署。 **學習資料** -- [線上文件](https://1panel.cn/docs/) +- [線上文件](https://docs.fit2cloud.com/1panel/) - [社區論壇](https://bbs.fit2cloud.com/c/1p/7) - [如何加入微信交流群?](https://bbs.fit2cloud.com/t/topic/2147)