feature: 1)检查更新功能,使用 github api 来获取版本数据;2)自动检查更新功能,可配置化。 (#303)
parent
178ac3c12b
commit
084e3dd886
|
@ -24,6 +24,8 @@ module.exports = {
|
|||
url: 'https://gitee.com/wangliang181230/dev-sidecar/raw/docmirror/packages/core/src/config/remote_config.json5'
|
||||
},
|
||||
theme: 'light', // 主题:light=亮色, dark=暗色
|
||||
autoChecked: true, // 是否自动检查更新
|
||||
skipPreRelease: true, // 是否忽略预发布版本
|
||||
dock: {
|
||||
hideWhenWinClose: false
|
||||
},
|
||||
|
|
|
@ -7,6 +7,9 @@ import fs from 'fs'
|
|||
import AdmZip from 'adm-zip'
|
||||
import log from '../../utils/util.log'
|
||||
import appPathUtil from '../../utils/util.apppath'
|
||||
import pkg from '../../../package.json'
|
||||
import DevSidecar from '@docmirror/dev-sidecar'
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const isMac = process.platform === 'darwin'
|
||||
const isLinux = process.platform === 'linux'
|
||||
|
@ -72,6 +75,104 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
|
|||
|
||||
let partPackagePath = null
|
||||
|
||||
// 检查更新
|
||||
const releasesApiUrl = 'https://api.github.com/repos/docmirror/dev-sidecar/releases'
|
||||
async function checkForUpdatesFromGitHub () {
|
||||
request(releasesApiUrl, { headers: { 'User-Agent': 'DS/' + pkg.version } }, (error, response, body) => {
|
||||
try {
|
||||
if (error) {
|
||||
log.error('检查更新失败:', error)
|
||||
const errorMsg = '检查更新失败:' + error
|
||||
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: errorMsg })
|
||||
return
|
||||
}
|
||||
if (response && response.statusCode === 200) {
|
||||
if (body == null || body.length < 2) {
|
||||
log.warn('检查更新失败,github API返回数据为空:', body)
|
||||
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败,github 返回数据为空' })
|
||||
return
|
||||
}
|
||||
|
||||
// 尝试解析API响应内容
|
||||
let data
|
||||
try {
|
||||
data = JSON.parse(body)
|
||||
} catch (e) {
|
||||
log.error('检查更新失败,github API返回数据格式不正确:', body)
|
||||
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败,github API返回数据格式不正确' })
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof data !== 'object' || data.length === undefined) {
|
||||
log.error('检查更新失败,github API返回数据不是数组:', body)
|
||||
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败,github API返回数据不是数组' })
|
||||
return
|
||||
}
|
||||
|
||||
// log.info('github api返回的release数据:', JSON.stringify(data, null, '\t'))
|
||||
|
||||
// 检查更新
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const versionData = data[i]
|
||||
|
||||
if (!versionData.assets || versionData.assets.length === 0) {
|
||||
continue // 跳过空版本,即上传过安装包
|
||||
}
|
||||
if (DevSidecar.api.config.get().app.skipPreRelease && versionData.name.indexOf('Pre-release') >= 0) {
|
||||
continue // 跳过预发布版本
|
||||
}
|
||||
|
||||
// log.info('最近正式版本数据:', versionData)
|
||||
|
||||
let version = versionData.tag_name
|
||||
if (version.indexOf('v') === 0) {
|
||||
version = version.substring(1)
|
||||
}
|
||||
if (version !== pkg.version) {
|
||||
log.info('检查更新-发现新版本:', version)
|
||||
win.webContents.send('update', {
|
||||
key: 'available',
|
||||
value: {
|
||||
version,
|
||||
releaseNotes: '发布公告:' + (versionData.html_url || ('https://github.com/docmirror/dev-sidecar/releases/tag/' + versionData.tag_name))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
log.info('检查更新-没有新版本,最新版本号为:', version)
|
||||
win.webContents.send('update', { key: 'notAvailable' })
|
||||
}
|
||||
|
||||
return // 只检查最近一个正式版本
|
||||
}
|
||||
|
||||
log.info('检查更新-没有正式版本数据')
|
||||
win.webContents.send('update', { key: 'notAvailable' })
|
||||
} else {
|
||||
log.error('检查更新失败, status:', response.statusCode, ', body:', body)
|
||||
|
||||
let bodyObj
|
||||
try {
|
||||
bodyObj = JSON.parse(body)
|
||||
} catch (e) {
|
||||
bodyObj = null
|
||||
}
|
||||
|
||||
let message
|
||||
if (response) {
|
||||
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : response.message) + ', code: ' + response.statusCode
|
||||
} else {
|
||||
message = '检查更新失败: ' + (bodyObj && bodyObj.message ? bodyObj.message : body)
|
||||
}
|
||||
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: message })
|
||||
}
|
||||
} catch (e) {
|
||||
log.error('检查更新失败:', e)
|
||||
win.webContents.send('update', { key: 'error', action: 'checkForUpdate', error: '检查更新失败:' + e.message })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 下载升级包
|
||||
function downloadPart (app, value) {
|
||||
const appPath = appPathUtil.getAppRootPath(app)
|
||||
const fileDir = path.join(appPath, 'update')
|
||||
|
@ -171,8 +272,11 @@ function updateHandle (app, api, win, beforeQuit, quit, log) {
|
|||
})
|
||||
} else if (arg.key === 'checkForUpdate') {
|
||||
// 执行自动更新检查
|
||||
log.info('autoUpdater checkForUpdates')
|
||||
autoUpdater.checkForUpdates()
|
||||
log.info('autoUpdater checkForUpdates:', arg.fromUser)
|
||||
|
||||
// 调用 github API,获取release数据,来检查更新
|
||||
// autoUpdater.checkForUpdates()
|
||||
checkForUpdatesFromGitHub()
|
||||
} else if (arg.key === 'downloadUpdate') {
|
||||
// 下载新版本
|
||||
log.info('autoUpdater downloadUpdate')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
function install (app, api) {
|
||||
const updateParams = app.$global.update = { fromUser: false, autoDownload: false, progress: 0, downloading: false, newVersion: false, isFullUpdate: true }
|
||||
const updateParams = app.$global.update = { fromUser: false, autoDownload: false, progress: 0, checking: false, downloading: false, newVersion: false, isFullUpdate: true }
|
||||
api.ipc.on('update', (event, message) => {
|
||||
console.log('on message', event, message)
|
||||
handleUpdateMessage(message, app)
|
||||
|
@ -10,6 +10,7 @@ function install (app, api) {
|
|||
if (fromUser != null) {
|
||||
updateParams.fromUser = fromUser
|
||||
}
|
||||
updateParams.checking = true
|
||||
api.ipc.send('update', { key: 'checkForUpdate', fromUser })
|
||||
},
|
||||
downloadUpdate () {
|
||||
|
@ -27,8 +28,11 @@ function install (app, api) {
|
|||
function handleUpdateMessage (message) {
|
||||
const type = message.key
|
||||
if (type === 'available') {
|
||||
updateParams.checking = false
|
||||
updateParams.newVersionData = message.value
|
||||
foundNewVersion(message.value)
|
||||
} else if (type === 'notAvailable') {
|
||||
updateParams.checking = false
|
||||
noNewVersion()
|
||||
} else if (type === 'downloaded') {
|
||||
// 更新包已下载完成,让用户确认是否更新
|
||||
|
@ -38,9 +42,15 @@ function install (app, api) {
|
|||
} else if (type === 'progress') {
|
||||
progressUpdate(message.value)
|
||||
} else if (type === 'error') {
|
||||
updateParams.checking = false
|
||||
updateParams.downloading = false
|
||||
const error = message.error
|
||||
app.$message.error((error == null ? '未知错误' : (error.stack || error).toString()))
|
||||
if (message.action === 'checkForUpdate' && updateParams.newVersionData) {
|
||||
// 如果检查更新报错了,但刚才成功拿到过一次数据,就拿之前的数据
|
||||
foundNewVersion(updateParams.newVersionData)
|
||||
} else {
|
||||
const error = message.error
|
||||
app.$message.error((error == null ? '未知错误' : (error.stack || error).toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,55 +65,67 @@ function install (app, api) {
|
|||
updateParams.progress = value
|
||||
}
|
||||
|
||||
function openGithubUrl () {
|
||||
api.ipc.openExternal('https://github.com/docmirror/dev-sidecar/releases')
|
||||
}
|
||||
|
||||
function goManualUpdate (value) {
|
||||
updateParams.newVersion = false
|
||||
app.$confirm({
|
||||
title: '暂不支持自动升级',
|
||||
// title: '暂不支持自动升级',
|
||||
title: '暂不提供自动升级',
|
||||
cancelText: '取消',
|
||||
okText: '确定',
|
||||
okText: '打开链接',
|
||||
width: 420,
|
||||
content: h => {
|
||||
function openGithubUrl () {
|
||||
api.ipc.openExternal('https://github.com/docmirror/dev-sidecar/releases')
|
||||
}
|
||||
return <div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> 下载新版本手动安装</div>
|
||||
return <div>
|
||||
<div>请前往 <a onClick={openGithubUrl}>github项目release页面</a> 下载新版本手动安装</div>
|
||||
<div><a onClick={openGithubUrl}>https://github.com/docmirror/dev-sidecar/releases</a></div>
|
||||
</div>
|
||||
},
|
||||
onOk () {
|
||||
openGithubUrl()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否小版本升级
|
||||
* @param value
|
||||
*/
|
||||
async function isSupportPartUpdate (value) {
|
||||
const info = await api.info.get()
|
||||
console.log('升级版本:', value.version)
|
||||
console.log('增量更新最小版本:', value.partMiniVersion)
|
||||
console.log('当前版本:', info.version)
|
||||
if (!value.partPackage) {
|
||||
return false
|
||||
}
|
||||
return !!(value.partMiniVersion && value.partMiniVersion < info.version)
|
||||
}
|
||||
// /**
|
||||
// * 是否小版本升级
|
||||
// * @param value
|
||||
// */
|
||||
// async function isSupportPartUpdate (value) {
|
||||
// const info = await api.info.get()
|
||||
// console.log('升级版本:', value.version)
|
||||
// console.log('增量更新最小版本:', value.partMiniVersion)
|
||||
// console.log('当前版本:', info.version)
|
||||
// if (!value.partPackage) {
|
||||
// return false
|
||||
// }
|
||||
// return !!(value.partMiniVersion && value.partMiniVersion < info.version)
|
||||
// }
|
||||
|
||||
async function downloadNewVersion (value) {
|
||||
const platform = await api.shell.getSystemPlatform()
|
||||
console.log(`download new version: ${JSON.stringify(value)}, platform: ${platform}`)
|
||||
if (platform === 'linux') {
|
||||
goManualUpdate(value)
|
||||
return
|
||||
}
|
||||
const partUpdate = await isSupportPartUpdate(value)
|
||||
if (partUpdate) {
|
||||
// 有增量更新
|
||||
api.update.downloadPart(value)
|
||||
} else {
|
||||
if (platform === 'mac') {
|
||||
goManualUpdate(value)
|
||||
return
|
||||
}
|
||||
updateParams.downloading = true
|
||||
api.update.downloadUpdate()
|
||||
}
|
||||
// 暂时取消自动更新功能
|
||||
goManualUpdate(value)
|
||||
|
||||
// const platform = await api.shell.getSystemPlatform()
|
||||
// console.log(`download new version: ${JSON.stringify(value)}, platform: ${platform}`)
|
||||
// if (platform === 'linux') {
|
||||
// goManualUpdate(value)
|
||||
// return
|
||||
// }
|
||||
// const partUpdate = await isSupportPartUpdate(value)
|
||||
// if (partUpdate) {
|
||||
// // 有增量更新
|
||||
// api.update.downloadPart(value)
|
||||
// } else {
|
||||
// if (platform === 'mac') {
|
||||
// goManualUpdate(value)
|
||||
// return
|
||||
// }
|
||||
// updateParams.downloading = true
|
||||
// api.update.downloadUpdate()
|
||||
// }
|
||||
}
|
||||
function foundNewVersion (value) {
|
||||
updateParams.newVersion = true
|
||||
|
@ -116,13 +138,14 @@ function install (app, api) {
|
|||
}
|
||||
console.log(value)
|
||||
app.$confirm({
|
||||
title: '发现新版本:' + value.version,
|
||||
title: '发现新版本:v' + value.version,
|
||||
cancelText: '暂不升级',
|
||||
okText: '升级',
|
||||
width: 710,
|
||||
content: h => {
|
||||
if (value.releaseNotes) {
|
||||
if (typeof value.releaseNotes === 'string') {
|
||||
return <div><div>更新内容:</div><div>{value.releaseNotes}</div></div>
|
||||
return <div>{value.releaseNotes}</div>
|
||||
} else {
|
||||
const notes = []
|
||||
for (const note of value.releaseNotes) {
|
||||
|
@ -144,24 +167,26 @@ function install (app, api) {
|
|||
|
||||
function newUpdateIsReady (value) {
|
||||
updateParams.downloading = false
|
||||
console.log(value)
|
||||
app.$confirm({
|
||||
title: `新版本(v${value.version})已准备好,是否立即升级?`,
|
||||
title: `新版本(v${value.version})已准备好,是否立即升级?`,
|
||||
cancelText: '暂不升级',
|
||||
okText: '立即升级',
|
||||
content: h => {
|
||||
console.log(value)
|
||||
if (value.releaseNotes) {
|
||||
const notes = []
|
||||
for (const note of value.releaseNotes) {
|
||||
notes.push(<li>{note}</li>)
|
||||
if (typeof value.releaseNotes === 'string') {
|
||||
return <div>{value.releaseNotes}</div>
|
||||
} else {
|
||||
const notes = []
|
||||
for (const note of value.releaseNotes) {
|
||||
notes.push(<li>{note}</li>)
|
||||
}
|
||||
return <div><div>更新内容:</div><ol>{notes}</ol></div>
|
||||
}
|
||||
return <div><div>更新内容:</div><ol>{notes}</ol></div>
|
||||
}
|
||||
},
|
||||
onOk () {
|
||||
api.update.doUpdateNow()
|
||||
},
|
||||
onCancel () {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
<a-badge :count="_rootCaSetuped?0:1" dot>安装根证书</a-badge>
|
||||
</a-button>
|
||||
|
||||
<a-button style="margin-right:10px" @click="doCheckUpdate(true)" :loading="update.downloading"
|
||||
<a-button style="margin-right:10px" @click="doCheckUpdate(true)" :loading="update.downloading || update.checking"
|
||||
:title="'当前版本:'+info.version">
|
||||
<a-badge :count="update.newVersion?1:0" dot>
|
||||
<span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '新版本下载中' : '检查更新' }}
|
||||
<span v-if="update.downloading">{{ update.progress }}%</span>{{ update.downloading ? '新版本下载中' : ('检查更新' + (update.checking ? '中' : '')) }}
|
||||
</a-badge>
|
||||
</a-button>
|
||||
</span>
|
||||
|
@ -161,7 +161,7 @@ export default {
|
|||
setupCa: {
|
||||
visible: false
|
||||
},
|
||||
update: { downloading: false, progress: 0, newVersion: false }
|
||||
update: { checking: false, downloading: false, progress: 0, newVersion: false }
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
|
@ -170,8 +170,8 @@ export default {
|
|||
this.$set(this, 'status', this.$status)
|
||||
this.switchBtns = this.createSwitchBtns()
|
||||
this.$set(this, 'update', this.$global.update)
|
||||
if (!this.update.autoChecked) {
|
||||
this.update.autoChecked = true
|
||||
if (!this.update.autoChecked && this.config.app.autoChecked) {
|
||||
this.update.autoChecked = true // 应用启动时,执行一次
|
||||
this.doCheckUpdate(false)
|
||||
}
|
||||
this.$api.info.get().then(ret => {
|
||||
|
|
|
@ -52,6 +52,32 @@
|
|||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="自动检查更新" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-radio-group v-model="config.app.autoChecked" default-value="light" button-style="solid">
|
||||
<a-radio-button :value="true">
|
||||
开启
|
||||
</a-radio-button>
|
||||
<a-radio-button :value="false">
|
||||
关闭
|
||||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
<div class="form-help">
|
||||
开启自动检查更新后,每次应用启动时会检查一次更新,如有新版本,则会弹出提示。
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="config.app.autoChecked" label="忽略预发布版本" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-radio-group v-model="config.app.skipPreRelease" default-value="light" button-style="solid">
|
||||
<a-radio-button :value="true">
|
||||
忽略
|
||||
</a-radio-button>
|
||||
<a-radio-button :value="false">
|
||||
不忽略
|
||||
</a-radio-button>
|
||||
<div class="form-help">
|
||||
预发布版本为版本号带有 “Pre-release” 的版本
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="首页提示" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-radio-group v-model="config.app.showShutdownTip"
|
||||
default-value="true" button-style="solid">
|
||||
|
|
Loading…
Reference in New Issue