feat: 增加内测模式 (#4685)

pull/4692/head
ssongliu 7 months ago committed by GitHub
parent 1381ef9e8e
commit 9cd37e8ec5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -8,6 +8,7 @@ type SettingInfo struct {
SystemIP string `json:"systemIP"` SystemIP string `json:"systemIP"`
SystemVersion string `json:"systemVersion"` SystemVersion string `json:"systemVersion"`
DockerSockPath string `json:"dockerSockPath"` DockerSockPath string `json:"dockerSockPath"`
DeveloperMode string `json:"developerMode"`
SessionTimeout string `json:"sessionTimeout"` SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"` LocalTime string `json:"localTime"`
@ -140,6 +141,7 @@ type SnapshotInfo struct {
} }
type UpgradeInfo struct { type UpgradeInfo struct {
TestVersion string `json:"testVersion"`
NewVersion string `json:"newVersion"` NewVersion string `json:"newVersion"`
LatestVersion string `json:"latestVersion"` LatestVersion string `json:"latestVersion"`
ReleaseNote string `json:"releaseNote"` ReleaseNote string `json:"releaseNote"`

@ -7,12 +7,11 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"strconv"
"strings" "strings"
"time" "time"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/cmd" "github.com/1Panel-dev/1Panel/backend/utils/cmd"
"github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/1Panel-dev/1Panel/backend/utils/common"
@ -37,45 +36,30 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
DeveloperMode, err := settingRepo.Get(settingRepo.WithByKey("DeveloperMode"))
latestVersion, err := u.loadVersion(true, currentVersion.Value)
if err != nil { if err != nil {
global.LOG.Infof("load latest version failed, err: %v", err)
return nil, err
}
if !common.ComparePanelVersion(string(latestVersion), currentVersion.Value) {
return nil, err return nil, err
} }
upgrade.LatestVersion = latestVersion
if latestVersion[0:4] == currentVersion.Value[0:4] { upgrade.TestVersion, upgrade.NewVersion, upgrade.LatestVersion = u.loadVersionByMode(DeveloperMode.Value, currentVersion.Value)
upgrade.NewVersion = ""
} else {
newerVersion, err := u.loadVersion(false, currentVersion.Value)
if err != nil {
global.LOG.Infof("load newer version failed, err: %v", err)
return nil, err
}
if newerVersion == currentVersion.Value {
upgrade.NewVersion = ""
} else {
upgrade.NewVersion = newerVersion
}
}
itemVersion := upgrade.LatestVersion itemVersion := upgrade.LatestVersion
if upgrade.NewVersion != "" { if upgrade.NewVersion != "" {
itemVersion = upgrade.NewVersion itemVersion = upgrade.NewVersion
} }
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion)) notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion))
if err != nil { if err != nil {
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", latestVersion, err) return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", itemVersion, err)
} }
upgrade.ReleaseNote = notes upgrade.ReleaseNote = notes
return &upgrade, nil return &upgrade, nil
} }
func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) { func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version, req.Version)) mode := global.CONF.System.Mode
if strings.Contains(req.Version, "beta") {
mode = "beta"
}
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, mode, req.Version, req.Version))
if err != nil { if err != nil {
return "", fmt.Errorf("load releases-notes of version %s failed, err: %v", req.Version, err) return "", fmt.Errorf("load releases-notes of version %s failed, err: %v", req.Version, err)
} }
@ -211,36 +195,92 @@ func (u *UpgradeService) handleRollback(originalDir string, errStep int) {
} }
} }
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (string, error) { func (u *UpgradeService) loadVersionByMode(developer, currentVersion string) (string, string, string) {
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode) var current, latest string
if global.CONF.System.Mode == "dev" {
betaVersionLatest := u.loadVersion(true, currentVersion, "beta")
devVersionLatest := u.loadVersion(true, currentVersion, "dev")
if common.ComparePanelVersion(betaVersionLatest, devVersionLatest) {
return betaVersionLatest, "", ""
}
return devVersionLatest, "", ""
}
latest = u.loadVersion(true, currentVersion, "stable")
current = u.loadVersion(false, currentVersion, "stable")
if len(developer) == 0 || developer == "disable" {
return "", current, latest
}
betaVersionLatest := u.loadVersion(true, currentVersion, "beta")
return betaVersionLatest, current, latest
}
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion, mode string) string {
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, mode)
if !isLatest { if !isLatest {
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, global.CONF.System.Mode) path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, mode)
} }
latestVersionRes, err := http.Get(path) latestVersionRes, err := http.Get(path)
if err != nil { if err != nil {
return "", buserr.New(constant.ErrOSSConn) global.LOG.Errorf("load latest version from oss failed, err: %v", err)
return ""
} }
defer latestVersionRes.Body.Close() defer latestVersionRes.Body.Close()
version, err := io.ReadAll(latestVersionRes.Body) versionByte, err := io.ReadAll(latestVersionRes.Body)
if err != nil { version := string(versionByte)
return "", buserr.New(constant.ErrOSSConn) if err != nil || strings.Contains(version, "<") {
global.LOG.Errorf("load latest version from oss failed, err: %v", version)
return ""
} }
if isLatest { if isLatest {
return string(version), nil return u.checkVersion(version, currentVersion)
} }
versionMap := make(map[string]string) versionMap := make(map[string]string)
if err := json.Unmarshal(version, &versionMap); err != nil { if err := json.Unmarshal(versionByte, &versionMap); err != nil {
return "", buserr.New(constant.ErrOSSConn) global.LOG.Errorf("load latest version from oss failed (error unmarshal), err: %v", err)
return ""
} }
if len(currentVersion) < 4 { versionPart := strings.Split(currentVersion, ".")
return "", fmt.Errorf("current version is error format: %s", currentVersion) if len(versionPart) < 3 {
global.LOG.Errorf("current version is error format: %s", currentVersion)
return ""
}
num, _ := strconv.Atoi(versionPart[1])
if num == 0 {
global.LOG.Errorf("current version is error format: %s", currentVersion)
return ""
}
if num >= 10 {
if version, ok := versionMap[currentVersion[0:5]]; ok {
return u.checkVersion(version, currentVersion)
}
return ""
} }
if version, ok := versionMap[currentVersion[0:4]]; ok { if version, ok := versionMap[currentVersion[0:4]]; ok {
return version, nil return u.checkVersion(version, currentVersion)
}
return ""
}
func (u *UpgradeService) checkVersion(v2, v1 string) string {
addSuffix := false
if !strings.Contains(v1, "-") {
v1 = v1 + "-lts"
}
if !strings.Contains(v2, "-") {
addSuffix = true
v2 = v2 + "-lts"
}
if common.ComparePanelVersion(v2, v1) {
if addSuffix {
return strings.TrimSuffix(v2, "-lts")
}
return v2
} }
return "", buserr.New(constant.ErrOSSConn) return ""
} }
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) { func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {

@ -81,6 +81,7 @@ func Init() {
migrations.AddNoAuthSetting, migrations.AddNoAuthSetting,
migrations.UpdateXpackHideMenu, migrations.UpdateXpackHideMenu,
migrations.AddMenuTabsSetting, migrations.AddMenuTabsSetting,
migrations.AddDeveloperSetting,
}) })
if err := m.Migrate(); err != nil { if err := m.Migrate(); err != nil {
global.LOG.Error(err) global.LOG.Error(err)

@ -144,3 +144,13 @@ var AddMenuTabsSetting = &gormigrate.Migration{
return nil return nil
}, },
} }
var AddDeveloperSetting = &gormigrate.Migration{
ID: "20240423-add-developer-setting",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "DeveloperMode", Value: "disable"}).Error; err != nil {
return err
}
return nil
},
}

@ -49,8 +49,8 @@ func ComparePanelVersion(version1, version2 string) bool {
if version1 == version2 { if version1 == version2 {
return false return false
} }
version1s := strings.Split(version1, ".") version1s := SplitStr(version1, ".", "-")
version2s := strings.Split(version2, ".") version2s := SplitStr(version2, ".", "-")
if len(version2s) > len(version1s) { if len(version2s) > len(version1s) {
for i := 0; i < len(version2s)-len(version1s); i++ { for i := 0; i < len(version2s)-len(version1s); i++ {
@ -68,7 +68,15 @@ func ComparePanelVersion(version1, version2 string) bool {
if version1s[i] == version2s[i] { if version1s[i] == version2s[i] {
continue continue
} else { } else {
return version1s[i] > version2s[i] v1, err1 := strconv.Atoi(version1s[i])
if err1 != nil {
return version1s[i] > version2s[i]
}
v2, err2 := strconv.Atoi(version2s[i])
if err2 != nil {
return version1s[i] > version2s[i]
}
return v1 > v2
} }
} }
return true return true
@ -296,3 +304,16 @@ func PunycodeEncode(text string) (string, error) {
} }
return ascii, nil return ascii, nil
} }
func SplitStr(str string, spi ...string) []string {
lists := []string{str}
var results []string
for _, s := range spi {
results = []string{}
for _, list := range lists {
results = append(results, strings.Split(list, s)...)
}
lists = results
}
return results
}

@ -14675,6 +14675,12 @@ const docTemplate = `{
"image": { "image": {
"type": "string" "type": "string"
}, },
"ipv4": {
"type": "string"
},
"ipv6": {
"type": "string"
},
"labels": { "labels": {
"type": "array", "type": "array",
"items": { "items": {
@ -17775,6 +17781,9 @@ const docTemplate = `{
"defaultNetwork": { "defaultNetwork": {
"type": "string" "type": "string"
}, },
"developerMode": {
"type": "string"
},
"dingVars": { "dingVars": {
"type": "string" "type": "string"
}, },
@ -17814,6 +17823,9 @@ const docTemplate = `{
"localTime": { "localTime": {
"type": "string" "type": "string"
}, },
"menuTabs": {
"type": "string"
},
"messageType": { "messageType": {
"type": "string" "type": "string"
}, },
@ -18076,6 +18088,9 @@ const docTemplate = `{
}, },
"releaseNote": { "releaseNote": {
"type": "string" "type": "string"
},
"testVersion": {
"type": "string"
} }
} }
}, },

@ -14668,6 +14668,12 @@
"image": { "image": {
"type": "string" "type": "string"
}, },
"ipv4": {
"type": "string"
},
"ipv6": {
"type": "string"
},
"labels": { "labels": {
"type": "array", "type": "array",
"items": { "items": {
@ -17768,6 +17774,9 @@
"defaultNetwork": { "defaultNetwork": {
"type": "string" "type": "string"
}, },
"developerMode": {
"type": "string"
},
"dingVars": { "dingVars": {
"type": "string" "type": "string"
}, },
@ -17807,6 +17816,9 @@
"localTime": { "localTime": {
"type": "string" "type": "string"
}, },
"menuTabs": {
"type": "string"
},
"messageType": { "messageType": {
"type": "string" "type": "string"
}, },
@ -18069,6 +18081,9 @@
}, },
"releaseNote": { "releaseNote": {
"type": "string" "type": "string"
},
"testVersion": {
"type": "string"
} }
} }
}, },

@ -444,6 +444,10 @@ definitions:
type: boolean type: boolean
image: image:
type: string type: string
ipv4:
type: string
ipv6:
type: string
labels: labels:
items: items:
type: string type: string
@ -2541,6 +2545,8 @@ definitions:
type: string type: string
defaultNetwork: defaultNetwork:
type: string type: string
developerMode:
type: string
dingVars: dingVars:
type: string type: string
dockerSockPath: dockerSockPath:
@ -2567,6 +2573,8 @@ definitions:
type: string type: string
localTime: localTime:
type: string type: string
menuTabs:
type: string
messageType: messageType:
type: string type: string
mfaInterval: mfaInterval:
@ -2740,6 +2748,8 @@ definitions:
type: string type: string
releaseNote: releaseNote:
type: string type: string
testVersion:
type: string
type: object type: object
dto.UserLoginInfo: dto.UserLoginInfo:
properties: properties:

@ -8,6 +8,7 @@ export namespace Setting {
systemIP: string; systemIP: string;
systemVersion: string; systemVersion: string;
dockerSockPath: string; dockerSockPath: string;
developerMode: string;
sessionTimeout: number; sessionTimeout: number;
localTime: string; localTime: string;

@ -50,9 +50,12 @@
<el-radio v-if="upgradeInfo.newVersion" :value="upgradeInfo.newVersion"> <el-radio v-if="upgradeInfo.newVersion" :value="upgradeInfo.newVersion">
{{ upgradeInfo.newVersion }} {{ $t('setting.newVersion') }} {{ upgradeInfo.newVersion }} {{ $t('setting.newVersion') }}
</el-radio> </el-radio>
<el-radio :value="upgradeInfo.latestVersion"> <el-radio v-if="upgradeInfo.latestVersion" :value="upgradeInfo.latestVersion">
{{ upgradeInfo.latestVersion }} {{ $t('setting.latestVersion') }} {{ upgradeInfo.latestVersion }} {{ $t('setting.latestVersion') }}
</el-radio> </el-radio>
<el-radio v-if="upgradeInfo.testVersion" :value="upgradeInfo.testVersion">
{{ upgradeInfo.testVersion }} {{ $t('setting.testVersion') }}
</el-radio>
</el-radio-group> </el-radio-group>
<MdEditor <MdEditor
v-model="upgradeInfo.releaseNote" v-model="upgradeInfo.releaseNote"
@ -124,13 +127,25 @@ const onLoadUpgradeInfo = async () => {
await loadUpgradeInfo() await loadUpgradeInfo()
.then((res) => { .then((res) => {
loading.value = false; loading.value = false;
if (!res.data) { if (res.data.testVersion || res.data.newVersion || res.data.latestVersion) {
upgradeInfo.value = res.data;
drawerVisible.value = true;
if (upgradeInfo.value.newVersion) {
upgradeVersion.value = upgradeInfo.value.newVersion;
return;
}
if (upgradeInfo.value.latestVersion) {
upgradeVersion.value = upgradeInfo.value.latestVersion;
return;
}
if (upgradeInfo.value.testVersion) {
upgradeVersion.value = upgradeInfo.value.testVersion;
return;
}
} else {
MsgSuccess(i18n.global.t('setting.noUpgrade')); MsgSuccess(i18n.global.t('setting.noUpgrade'));
return; return;
} }
upgradeInfo.value = res.data;
upgradeVersion.value = upgradeInfo.value.newVersion || upgradeInfo.value.latestVersion;
drawerVisible.value = true;
}) })
.catch(() => { .catch(() => {
loading.value = false; loading.value = false;

@ -1266,6 +1266,7 @@ const message = {
noSpace: 'Input information cannot include space characters', noSpace: 'Input information cannot include space characters',
duplicatePassword: 'The new password cannot be the same as the original password, please re-enter!', duplicatePassword: 'The new password cannot be the same as the original password, please re-enter!',
diskClean: 'Cache Clean', diskClean: 'Cache Clean',
developerMode: 'Internal mode',
thirdParty: 'Third-party account', thirdParty: 'Third-party account',
createBackupAccount: 'Add {0}', createBackupAccount: 'Add {0}',
@ -1468,6 +1469,7 @@ const message = {
'Name rules: [major version].[functional version].[Bug fix version], as shown in the following example:', 'Name rules: [major version].[functional version].[Bug fix version], as shown in the following example:',
versionHelper1: 'v1.0.1 is a Bug fix after v1.0.0', versionHelper1: 'v1.0.1 is a Bug fix after v1.0.0',
versionHelper2: 'v1.1.0 is a feature release after v1.0.0', versionHelper2: 'v1.1.0 is a feature release after v1.0.0',
testVersion: '(Beta version)',
newVersion: '(Bug fix version)', newVersion: '(Bug fix version)',
latestVersion: '(Functional version)', latestVersion: '(Functional version)',
upgradeCheck: 'Check for updates', upgradeCheck: 'Check for updates',

@ -1189,6 +1189,7 @@ const message = {
noSpace: '', noSpace: '',
duplicatePassword: '', duplicatePassword: '',
diskClean: '', diskClean: '',
developerMode: '',
thirdParty: '', thirdParty: '',
createBackupAccount: ' {0}', createBackupAccount: ' {0}',
@ -1295,6 +1296,7 @@ const message = {
versionHelper: '1Panel [].[].[Bug ]', versionHelper: '1Panel [].[].[Bug ]',
versionHelper1: 'v1.0.1 v1.0.0 Bug ', versionHelper1: 'v1.0.1 v1.0.0 Bug ',
versionHelper2: 'v1.1.0 v1.0.0 ', versionHelper2: 'v1.1.0 v1.0.0 ',
testVersion: '()',
newVersion: '(Bug )', newVersion: '(Bug )',
latestVersion: '()', latestVersion: '()',
upgradeCheck: '', upgradeCheck: '',

@ -1190,6 +1190,7 @@ const message = {
noSpace: '', noSpace: '',
duplicatePassword: '', duplicatePassword: '',
diskClean: '', diskClean: '',
developerMode: '',
thirdParty: '', thirdParty: '',
createBackupAccount: ' {0}', createBackupAccount: ' {0}',
@ -1296,6 +1297,7 @@ const message = {
versionHelper: '1Panel [].[].[Bug ]', versionHelper: '1Panel [].[].[Bug ]',
versionHelper1: 'v1.0.1 v1.0.0 Bug ', versionHelper1: 'v1.0.1 v1.0.0 Bug ',
versionHelper2: 'v1.1.0 v1.0.0 ', versionHelper2: 'v1.1.0 v1.0.0 ',
testVersion: '()',
newVersion: '(Bug )', newVersion: '(Bug )',
latestVersion: '()', latestVersion: '()',
upgradeCheck: '', upgradeCheck: '',

@ -542,7 +542,7 @@ const hideEntrance = () => {
const loadUpgradeStatus = async () => { const loadUpgradeStatus = async () => {
const res = await loadUpgradeInfo(); const res = await loadUpgradeInfo();
if (res.data) { if (res.data.testVersion || res.data.newVersion || res.data.latestVersion) {
globalStore.hasNewVersion = true; globalStore.hasNewVersion = true;
} else { } else {
globalStore.hasNewVersion = false; globalStore.hasNewVersion = false;

@ -113,6 +113,20 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item :label="$t('setting.developerMode')" prop="developerMode">
<el-radio-group
@change="onSave('DeveloperMode', form.developerMode)"
v-model="form.developerMode"
>
<el-radio-button value="enable">
<span>{{ $t('commons.button.enable') }}</span>
</el-radio-button>
<el-radio-button value="disable">
<span>{{ $t('commons.button.disable') }}</span>
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('setting.advancedMenuHide')"> <el-form-item :label="$t('setting.advancedMenuHide')">
<el-input disabled v-model="form.proHideMenus"> <el-input disabled v-model="form.proHideMenus">
<template #append> <template #append>
@ -176,6 +190,7 @@ const form = reactive({
complexityVerification: '', complexityVerification: '',
defaultNetwork: '', defaultNetwork: '',
defaultNetworkVal: '', defaultNetworkVal: '',
developerMode: '',
proHideMenus: ref(i18n.t('setting.unSetting')), proHideMenus: ref(i18n.t('setting.unSetting')),
hideMenuList: '', hideMenuList: '',
@ -219,6 +234,7 @@ const search = async () => {
form.defaultNetworkVal = res.data.defaultNetwork === 'all' ? i18n.t('commons.table.all') : res.data.defaultNetwork; form.defaultNetworkVal = res.data.defaultNetwork === 'all' ? i18n.t('commons.table.all') : res.data.defaultNetwork;
form.proHideMenus = res.data.xpackHideMenu; form.proHideMenus = res.data.xpackHideMenu;
form.hideMenuList = res.data.xpackHideMenu; form.hideMenuList = res.data.xpackHideMenu;
form.developerMode = res.data.developerMode;
// title // title
const json: Node = JSON.parse(res.data.xpackHideMenu); const json: Node = JSON.parse(res.data.xpackHideMenu);

Loading…
Cancel
Save