feat: add version checking for GitHub releases and improve error handling

This commit is contained in:
twwu 2024-11-18 11:54:51 +08:00
parent 07494459cc
commit 87ca20c047
4 changed files with 52 additions and 32 deletions

View File

@ -2,6 +2,8 @@ import Toast from '@/app/components/base/toast'
import { uploadGitHub } from '@/service/plugins'
import { Octokit } from '@octokit/core'
import { GITHUB_ACCESS_TOKEN } from '@/config'
import { compareVersion, getLatestVersion } from '@/utils/semver'
import type { GitHubRepoReleaseResponse } from '../types'
export const useGitHubReleases = () => {
const fetchReleases = async (owner: string, repo: string) => {
@ -37,7 +39,21 @@ export const useGitHubReleases = () => {
}
}
return { fetchReleases }
const checkForUpdates = (fetchedReleases: GitHubRepoReleaseResponse[], currentVersion: string) => {
if (fetchedReleases.length === 0) throw new Error('No releases found')
const versions = fetchedReleases.map(release => release.tag_name)
const latestVersion = getLatestVersion(versions)
let res = false
try {
res = compareVersion(latestVersion, currentVersion) === 1
}
catch {
throw new Error('Failed to compare versions, please check the version format.')
}
return res
}
return { fetchReleases, checkForUpdates }
}
export const useGitHubUpload = () => {

View File

@ -15,7 +15,6 @@ import Icon from '../card/base/card-icon'
import Title from '../card/base/title'
import OrgInfo from '../card/base/org-info'
import { useGitHubReleases } from '../install-plugin/hooks'
import { compareVersion, getLatestVersion } from '@/utils/semver'
import PluginVersionPicker from '@/app/components/plugins/update-plugin/plugin-version-picker'
import UpdateFromMarketplace from '@/app/components/plugins/update-plugin/from-market-place'
import OperationDropdown from '@/app/components/plugins/plugin-detail-panel/operation-dropdown'
@ -49,7 +48,7 @@ const DetailHeader = ({
}: Props) => {
const { t } = useTranslation()
const locale = useGetLanguage()
const { fetchReleases } = useGitHubReleases()
const { checkForUpdates, fetchReleases } = useGitHubReleases()
const { setShowUpdatePluginModal } = useModalContext()
const {
@ -72,14 +71,11 @@ const DetailHeader = ({
unique_identifier: latest_unique_identifier,
})
const hasNewVersion = useMemo(() => {
if (isFromGitHub)
return latest_version !== version
if (isFromMarketplace)
return !!latest_version && latest_version !== version
return false
}, [isFromGitHub, isFromMarketplace, latest_version, version])
}, [isFromMarketplace, latest_version, version])
const [isShowUpdateModal, {
setTrue: showUpdateModal,
@ -94,11 +90,7 @@ const DetailHeader = ({
try {
const fetchedReleases = await fetchReleases(author, name)
if (fetchedReleases.length === 0)
return
const versions = fetchedReleases.map(release => release.tag_name)
const latestVersion = getLatestVersion(versions)
if (compareVersion(latestVersion, version) === 1) {
if (checkForUpdates(fetchedReleases, meta!.version)) {
setShowUpdatePluginModal({
onSaveCallback: () => {
onUpdate()
@ -107,7 +99,7 @@ const DetailHeader = ({
type: PluginSource.github,
github: {
originalPackageInfo: {
id: installation_id,
id: detail.plugin_unique_identifier,
repo: meta!.repo,
version: meta!.version,
package: meta!.package,
@ -124,11 +116,19 @@ const DetailHeader = ({
})
}
}
catch {
Toast.notify({
type: 'error',
message: 'Failed to compare versions',
})
catch (error) {
if (error instanceof Error) {
Toast.notify({
type: 'error',
message: error.message,
})
}
else {
Toast.notify({
type: 'error',
message: 'Failed to compare versions',
})
}
}
}
@ -203,7 +203,7 @@ const DetailHeader = ({
/>
}
/>
{hasNewVersion && (
{(hasNewVersion || isFromGitHub) && (
<Button variant='secondary-accent' size='small' className='!h-5' onClick={handleUpdate}>{t('plugin.detailPanel.operation.update')}</Button>
)}
</div>

View File

@ -11,7 +11,6 @@ import Tooltip from '../../base/tooltip'
import Confirm from '../../base/confirm'
import { uninstallPlugin } from '@/service/plugins'
import { useGitHubReleases } from '../install-plugin/hooks'
import { compareVersion, getLatestVersion } from '@/utils/semver'
import Toast from '@/app/components/base/toast'
import { useModalContext } from '@/context/modal-context'
import { useInvalidateInstalledPluginList } from '@/service/use-plugins'
@ -50,18 +49,14 @@ const Action: FC<Props> = ({
setTrue: showDeleting,
setFalse: hideDeleting,
}] = useBoolean(false)
const { fetchReleases } = useGitHubReleases()
const { checkForUpdates, fetchReleases } = useGitHubReleases()
const { setShowUpdatePluginModal } = useModalContext()
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const handleFetchNewVersion = async () => {
try {
const fetchedReleases = await fetchReleases(author, pluginName)
if (fetchedReleases.length === 0)
return
const versions = fetchedReleases.map(release => release.tag_name)
const latestVersion = getLatestVersion(versions)
if (compareVersion(latestVersion, meta!.version) === 1) {
if (checkForUpdates(fetchedReleases, meta!.version)) {
setShowUpdatePluginModal({
onSaveCallback: () => {
invalidateInstalledPluginList()
@ -87,11 +82,19 @@ const Action: FC<Props> = ({
})
}
}
catch {
Toast.notify({
type: 'error',
message: 'Failed to compare versions',
})
catch (error) {
if (error instanceof Error) {
Toast.notify({
type: 'error',
message: error.message,
})
}
else {
Toast.notify({
type: 'error',
message: 'Failed to compare versions',
})
}
}
}
@ -108,6 +111,7 @@ const Action: FC<Props> = ({
hideDeleteConfirm()
onDelete()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [installationId, onDelete])
return (
<div className='flex space-x-1'>

View File

@ -82,7 +82,7 @@ const PluginItem: FC<Props> = ({
<div className="flex items-center h-5">
<Title title={label[locale]} />
{verified && <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />}
<Badge className='ml-1' text={plugin.version} />
<Badge className='ml-1' text={source === PluginSource.github ? plugin.meta!.version : plugin.version} />
</div>
<div className='flex items-center justify-between'>
<Description text={description[locale]} descriptionLineRows={1}></Description>