feat: refactor GitHub releases fetching and update handling with improved error notifications

This commit is contained in:
twwu 2024-11-19 11:20:17 +08:00
parent d3fe6fd303
commit 87b23a1fac
6 changed files with 114 additions and 102 deletions

View File

@ -1,26 +1,16 @@
import Toast from '@/app/components/base/toast'
import Toast, { type IToastProps } 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) => {
try {
const octokit = new Octokit({
auth: GITHUB_ACCESS_TOKEN,
})
const res = await octokit.request('GET /repos/{owner}/{repo}/releases', {
owner,
repo,
headers: {
'X-GitHub-Api-Version': '2022-11-28',
},
})
if (res.status !== 200) throw new Error('Failed to fetch releases')
const res = await fetch(`/repos/${owner}/${repo}/releases`)
const bodyJson = await res.json()
if (bodyJson.status !== 200) throw new Error(bodyJson.data.message)
const formattedReleases = res.data.map((release: any) => ({
const formattedReleases = bodyJson.data.map((release: any) => ({
tag_name: release.tag_name,
assets: release.assets.map((asset: any) => ({
browser_download_url: asset.browser_download_url,
@ -31,26 +21,46 @@ export const useGitHubReleases = () => {
return formattedReleases
}
catch (error) {
Toast.notify({
type: 'error',
message: 'Failed to fetch repository releases',
})
if (error instanceof Error) {
Toast.notify({
type: 'error',
message: error.message,
})
}
else {
Toast.notify({
type: 'error',
message: 'Failed to fetch repository releases',
})
}
return []
}
}
const checkForUpdates = (fetchedReleases: GitHubRepoReleaseResponse[], currentVersion: string) => {
if (fetchedReleases.length === 0) throw new Error('No releases found')
let needUpdate = false
const toastProps: IToastProps = {
type: 'info',
message: 'No new version available',
}
if (fetchedReleases.length === 0) {
toastProps.type = 'error'
toastProps.message = 'Input releases is empty'
return { needUpdate, toastProps }
}
const versions = fetchedReleases.map(release => release.tag_name)
const latestVersion = getLatestVersion(versions)
let res = false
try {
res = compareVersion(latestVersion, currentVersion) === 1
needUpdate = compareVersion(latestVersion, currentVersion) === 1
if (needUpdate)
toastProps.message = `New version available: ${latestVersion}`
}
catch {
throw new Error('Failed to compare versions, please check the version format.')
needUpdate = false
toastProps.type = 'error'
toastProps.message = 'Fail to compare versions, please check the version format'
}
return res
return { needUpdate, toastProps }
}
return { fetchReleases, checkForUpdates }

View File

@ -88,47 +88,28 @@ const DetailHeader = ({
return
}
try {
const fetchedReleases = await fetchReleases(author, name)
if (checkForUpdates(fetchedReleases, meta!.version)) {
setShowUpdatePluginModal({
onSaveCallback: () => {
onUpdate()
},
payload: {
type: PluginSource.github,
github: {
originalPackageInfo: {
id: detail.plugin_unique_identifier,
repo: meta!.repo,
version: meta!.version,
package: meta!.package,
releases: fetchedReleases,
},
const fetchedReleases = await fetchReleases(author, name)
if (fetchedReleases.length === 0) return
const { needUpdate, toastProps } = checkForUpdates(fetchedReleases, meta!.version)
Toast.notify(toastProps)
if (needUpdate) {
setShowUpdatePluginModal({
onSaveCallback: () => {
onUpdate()
},
payload: {
type: PluginSource.github,
github: {
originalPackageInfo: {
id: detail.plugin_unique_identifier,
repo: meta!.repo,
version: meta!.version,
package: meta!.package,
releases: fetchedReleases,
},
},
})
}
else {
Toast.notify({
type: 'info',
message: 'No new version available',
})
}
}
catch (error) {
if (error instanceof Error) {
Toast.notify({
type: 'error',
message: error.message,
})
}
else {
Toast.notify({
type: 'error',
message: 'Failed to compare versions',
})
}
},
})
}
}

View File

@ -54,47 +54,28 @@ const Action: FC<Props> = ({
const invalidateInstalledPluginList = useInvalidateInstalledPluginList()
const handleFetchNewVersion = async () => {
try {
const fetchedReleases = await fetchReleases(author, pluginName)
if (checkForUpdates(fetchedReleases, meta!.version)) {
setShowUpdatePluginModal({
onSaveCallback: () => {
invalidateInstalledPluginList()
},
payload: {
type: PluginSource.github,
github: {
originalPackageInfo: {
id: pluginUniqueIdentifier,
repo: meta!.repo,
version: meta!.version,
package: meta!.package,
releases: fetchedReleases,
},
const fetchedReleases = await fetchReleases(author, pluginName)
if (fetchReleases.length === 0) return
const { needUpdate, toastProps } = checkForUpdates(fetchedReleases, meta!.version)
Toast.notify(toastProps)
if (needUpdate) {
setShowUpdatePluginModal({
onSaveCallback: () => {
invalidateInstalledPluginList()
},
payload: {
type: PluginSource.github,
github: {
originalPackageInfo: {
id: pluginUniqueIdentifier,
repo: meta!.repo,
version: meta!.version,
package: meta!.package,
releases: fetchedReleases,
},
},
})
}
else {
Toast.notify({
type: 'info',
message: 'No new version available',
})
}
}
catch (error) {
if (error instanceof Error) {
Toast.notify({
type: 'error',
message: error.message,
})
}
else {
Toast.notify({
type: 'error',
message: 'Failed to compare versions',
})
}
},
})
}
}

View File

@ -0,0 +1,36 @@
import { type NextRequest, NextResponse } from 'next/server'
import { Octokit } from '@octokit/core'
import { RequestError } from '@octokit/request-error'
import { GITHUB_ACCESS_TOKEN } from '@/config'
type Params = {
owner: string,
repo: string,
}
const octokit = new Octokit({
auth: GITHUB_ACCESS_TOKEN,
})
export async function GET(
request: NextRequest,
{ params }: { params: Promise<Params> },
) {
const { owner, repo } = (await params)
try {
const releasesRes = await octokit.request('GET /repos/{owner}/{repo}/releases', {
owner,
repo,
headers: {
'X-GitHub-Api-Version': '2022-11-28',
},
})
return NextResponse.json(releasesRes)
}
catch (error) {
if (error instanceof RequestError)
return NextResponse.json(error.response)
else
throw error
}
}

View File

@ -38,6 +38,7 @@
"@monaco-editor/react": "^4.6.0",
"@next/mdx": "^14.0.4",
"@octokit/core": "^6.1.2",
"@octokit/request-error": "^6.1.5",
"@remixicon/react": "^4.3.0",
"@sentry/react": "^7.54.0",
"@sentry/utils": "^7.54.0",

View File

@ -55,6 +55,9 @@ importers:
'@octokit/core':
specifier: ^6.1.2
version: 6.1.2
'@octokit/request-error':
specifier: ^6.1.5
version: 6.1.5
'@remixicon/react':
specifier: ^4.3.0
version: 4.3.0(react@18.2.0)