mirror of
https://github.com/EasyTier/easytier.github.io.git
synced 2026-10-19 16:16:34 +00:00
修复下载页面的稳定版、预发布版和 Nightly 通道 (#326)
下载页面目前只有稳定版和预发布版两个通道,并将 GitHub 返回的第一个预发布版本作为普通预发布版。官方新增 Nightly 后,这会误选 `nightly`,并拼出错误的版本标签和下载地址。 此次修改为中英文下载页面补齐稳定版、预发布版、开发版(Nightly)三个通道。普通预发布版明确排除 Nightly 和草稿;下载链接按发布资产中的真实文件名和地址匹配,支持 Nightly 标签与安装包版本号不同的情况。 各通道分别处理接口失败,稳定版和预发布版保留版本回退,Nightly 无法加载或暂无资产时提供官方发布页入口。同步将预发布版回退版本更新为 `2.7.0`。 验证: - `pnpm docs:build` 构建通过。 - `pnpm exec eslint useLatestVersion.ts releaseUtils.ts metadata.data.ts tests/releaseUtils.test.ts` 检查通过。 - `node --experimental-strip-types --test tests/releaseUtils.test.ts`:6 项回归测试通过,覆盖通道区分、Nightly 下载地址、GUI 资产版本差异、Android 安装包、缺失资产和接口失败回退。 - 浏览器验证中英文通道切换、操作系统和架构筛选、GitHub 加速前缀及构建后的页面预览。 Co-authored-by: Codex <codex@local>
This commit is contained in:
+33
-14
@@ -5,15 +5,16 @@ home: hello
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { data } from '../../metadata.data.js'
|
import { data } from '../../metadata.data.js'
|
||||||
|
import { resolveDownloadUrl } from '../../releaseUtils.ts'
|
||||||
import { useLatestVersion } from '../../useLatestVersion.ts'
|
import { useLatestVersion } from '../../useLatestVersion.ts'
|
||||||
|
|
||||||
const { latestVersion, prereleaseVersion, loading, error } = useLatestVersion()
|
const { latestVersion, prereleaseVersion, latestRelease, prereleaseRelease, nightlyRelease, loading } = useLatestVersion()
|
||||||
|
|
||||||
interface Package {
|
interface Package {
|
||||||
os: string
|
os: string
|
||||||
arch: string
|
arch: string
|
||||||
gui_pkg_tmpl: record<string, string>
|
gui_pkg_tmpl: Record<string, string>
|
||||||
cli_pkg_tmpl: record<string, string> // key: format, value: url
|
cli_pkg_tmpl: Record<string, string> // key: format, value: url
|
||||||
comment?: string
|
comment?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,20 +158,30 @@ const all_proxy = new Set(data.github_accels)
|
|||||||
|
|
||||||
const channel = ref('easytier_latest_version')
|
const channel = ref('easytier_latest_version')
|
||||||
|
|
||||||
const url = 'https://github.com/EasyTier/EasyTier/releases/tag/v'
|
const url = 'https://github.com/EasyTier/EasyTier/releases/tag/'
|
||||||
const filter_os = ref('')
|
const filter_os = ref('')
|
||||||
const filter_arch = ref('')
|
const filter_arch = ref('')
|
||||||
const accel_proxy = ref('')
|
const accel_proxy = ref('')
|
||||||
|
|
||||||
const vers = computed(() => ({
|
const vers = computed(() => ({
|
||||||
easytier_latest_version: (!loading.value && !error.value && latestVersion.value) ? latestVersion.value : data.easytier_latest_version,
|
easytier_latest_version: latestVersion.value ?? data.easytier_latest_version,
|
||||||
easytier_pre_release_version: (!loading.value && !error.value && prereleaseVersion.value) ? prereleaseVersion.value : data.easytier_pre_release_version,
|
easytier_pre_release_version: prereleaseVersion.value ?? data.easytier_pre_release_version,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const currentVersion = computed(() => vers.value[channel.value as keyof typeof vers.value])
|
const currentVersion = computed(() => vers.value[channel.value as keyof typeof vers.value])
|
||||||
|
const currentRelease = computed(() => {
|
||||||
|
if (channel.value === 'nightly')
|
||||||
|
return nightlyRelease.value
|
||||||
|
return channel.value === 'easytier_latest_version' ? latestRelease.value : prereleaseRelease.value
|
||||||
|
})
|
||||||
|
const currentTag = computed(() => channel.value === 'nightly' ? 'nightly' : currentRelease.value?.tag_name ?? `v${currentVersion.value}`)
|
||||||
|
const currentTitle = computed(() => channel.value === 'nightly' ? 'Nightly' : currentTag.value)
|
||||||
|
|
||||||
function renderUrlTmpl(url_tmpl: string): string {
|
function renderLinks(templates: Record<string, string>) {
|
||||||
return accel_proxy.value + url_tmpl.replace(/\{\}/g, currentVersion.value)
|
return Object.entries(templates).flatMap(([format, template]) => {
|
||||||
|
const downloadUrl = resolveDownloadUrl(template, currentRelease.value, channel.value === 'nightly' ? undefined : currentVersion.value)
|
||||||
|
return downloadUrl ? [{ format, url: accel_proxy.value + downloadUrl }] : []
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -192,10 +203,18 @@ The command line program package includes four executables:
|
|||||||
<select name="channel-select" id="channel-select" v-model="channel" class="filter-select">
|
<select name="channel-select" id="channel-select" v-model="channel" class="filter-select">
|
||||||
<option value="easytier_latest_version"> Stable Version(v{{ vers.easytier_latest_version }}) </option>
|
<option value="easytier_latest_version"> Stable Version(v{{ vers.easytier_latest_version }}) </option>
|
||||||
<option value="easytier_pre_release_version"> Pre-release Version(v{{ vers.easytier_pre_release_version }}) </option>
|
<option value="easytier_pre_release_version"> Pre-release Version(v{{ vers.easytier_pre_release_version }}) </option>
|
||||||
|
<option value="nightly"> Development (Nightly) </option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## <a :href="url + currentVersion">EasyTier v{{ currentVersion }}</a> { #latest }
|
<p v-if="channel === 'nightly'">Nightly follows the main branch and is intended for testing the latest features. It may be unstable.</p>
|
||||||
|
|
||||||
|
## <a :href="url + currentTag">EasyTier {{ currentTitle }}</a> { #latest }
|
||||||
|
|
||||||
|
<p v-if="channel === 'nightly' && !nightlyRelease?.assets.length">
|
||||||
|
<span v-if="loading">Loading Nightly downloads…</span>
|
||||||
|
<span v-else>Nightly downloads could not be loaded. Please visit the <a :href="url + 'nightly'">Nightly release page</a>.</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
- GitHub Acceleration
|
- GitHub Acceleration
|
||||||
<div>
|
<div>
|
||||||
@@ -221,7 +240,7 @@ The command line program package includes four executables:
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table>
|
<table v-if="channel !== 'nightly' || nightlyRelease?.assets.length">
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -239,14 +258,14 @@ The command line program package includes four executables:
|
|||||||
<td> {{ pkg.arch }} </td>
|
<td> {{ pkg.arch }} </td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<a v-for="(url_tmpl, format) in pkg.gui_pkg_tmpl" class="download-link-span" :href="renderUrlTmpl(url_tmpl)">
|
<a v-for="link in renderLinks(pkg.gui_pkg_tmpl)" :key="link.format" class="download-link-span" :href="link.url">
|
||||||
{{format}}
|
{{link.format}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<a v-for="(url_tmpl, format) in pkg.cli_pkg_tmpl" class="download-link-span" :href="renderUrlTmpl(url_tmpl)">
|
<a v-for="link in renderLinks(pkg.cli_pkg_tmpl)" :key="link.format" class="download-link-span" :href="link.url">
|
||||||
{{format}}
|
{{link.format}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|||||||
+33
-14
@@ -5,15 +5,16 @@ home: hello
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { data } from '../metadata.data.js'
|
import { data } from '../metadata.data.js'
|
||||||
|
import { resolveDownloadUrl } from '../releaseUtils.ts'
|
||||||
import { useLatestVersion } from '../useLatestVersion.ts'
|
import { useLatestVersion } from '../useLatestVersion.ts'
|
||||||
|
|
||||||
const { latestVersion, prereleaseVersion, loading, error } = useLatestVersion()
|
const { latestVersion, prereleaseVersion, latestRelease, prereleaseRelease, nightlyRelease, loading } = useLatestVersion()
|
||||||
|
|
||||||
interface Package {
|
interface Package {
|
||||||
os: string
|
os: string
|
||||||
arch: string
|
arch: string
|
||||||
gui_pkg_tmpl: record<string, string>
|
gui_pkg_tmpl: Record<string, string>
|
||||||
cli_pkg_tmpl: record<string, string> // key: format, value: url
|
cli_pkg_tmpl: Record<string, string> // key: format, value: url
|
||||||
comment?: string
|
comment?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,20 +158,30 @@ const all_proxy = new Set(data.github_accels)
|
|||||||
|
|
||||||
const channel = ref('easytier_latest_version')
|
const channel = ref('easytier_latest_version')
|
||||||
|
|
||||||
const url = 'https://github.com/EasyTier/EasyTier/releases/tag/v'
|
const url = 'https://github.com/EasyTier/EasyTier/releases/tag/'
|
||||||
const filter_os = ref('')
|
const filter_os = ref('')
|
||||||
const filter_arch = ref('')
|
const filter_arch = ref('')
|
||||||
const accel_proxy = ref('')
|
const accel_proxy = ref('')
|
||||||
|
|
||||||
const vers = computed(() => ({
|
const vers = computed(() => ({
|
||||||
easytier_latest_version: (!loading.value && !error.value && latestVersion.value) ? latestVersion.value : data.easytier_latest_version,
|
easytier_latest_version: latestVersion.value ?? data.easytier_latest_version,
|
||||||
easytier_pre_release_version: (!loading.value && !error.value && prereleaseVersion.value) ? prereleaseVersion.value : data.easytier_pre_release_version,
|
easytier_pre_release_version: prereleaseVersion.value ?? data.easytier_pre_release_version,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const currentVersion = computed(() => vers.value[channel.value as keyof typeof vers.value])
|
const currentVersion = computed(() => vers.value[channel.value as keyof typeof vers.value])
|
||||||
|
const currentRelease = computed(() => {
|
||||||
|
if (channel.value === 'nightly')
|
||||||
|
return nightlyRelease.value
|
||||||
|
return channel.value === 'easytier_latest_version' ? latestRelease.value : prereleaseRelease.value
|
||||||
|
})
|
||||||
|
const currentTag = computed(() => channel.value === 'nightly' ? 'nightly' : currentRelease.value?.tag_name ?? `v${currentVersion.value}`)
|
||||||
|
const currentTitle = computed(() => channel.value === 'nightly' ? 'Nightly' : currentTag.value)
|
||||||
|
|
||||||
function renderUrlTmpl(url_tmpl: string): string {
|
function renderLinks(templates: Record<string, string>) {
|
||||||
return accel_proxy.value + url_tmpl.replace(/\{\}/g, currentVersion.value)
|
return Object.entries(templates).flatMap(([format, template]) => {
|
||||||
|
const downloadUrl = resolveDownloadUrl(template, currentRelease.value, channel.value === 'nightly' ? undefined : currentVersion.value)
|
||||||
|
return downloadUrl ? [{ format, url: accel_proxy.value + downloadUrl }] : []
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -192,10 +203,18 @@ function renderUrlTmpl(url_tmpl: string): string {
|
|||||||
<select name="channel-select" id="channel-select" v-model="channel" class="filter-select">
|
<select name="channel-select" id="channel-select" v-model="channel" class="filter-select">
|
||||||
<option value="easytier_latest_version"> 稳定版(v{{ vers.easytier_latest_version }}) </option>
|
<option value="easytier_latest_version"> 稳定版(v{{ vers.easytier_latest_version }}) </option>
|
||||||
<option value="easytier_pre_release_version"> 预发布版(v{{ vers.easytier_pre_release_version }}) </option>
|
<option value="easytier_pre_release_version"> 预发布版(v{{ vers.easytier_pre_release_version }}) </option>
|
||||||
|
<option value="nightly"> 开发版(Nightly) </option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## <a :href="url + currentVersion">EasyTier v{{ currentVersion }}</a> { #latest }
|
<p v-if="channel === 'nightly'">Nightly 跟随 main 分支更新,适合测试最新功能,可能不稳定。</p>
|
||||||
|
|
||||||
|
## <a :href="url + currentTag">EasyTier {{ currentTitle }}</a> { #latest }
|
||||||
|
|
||||||
|
<p v-if="channel === 'nightly' && !nightlyRelease?.assets.length">
|
||||||
|
<span v-if="loading">正在加载 Nightly 下载文件…</span>
|
||||||
|
<span v-else>暂时无法获取 Nightly 下载文件,请前往 <a :href="url + 'nightly'">Nightly 发布页</a>。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
- Github 加速
|
- Github 加速
|
||||||
<div>
|
<div>
|
||||||
@@ -221,7 +240,7 @@ function renderUrlTmpl(url_tmpl: string): string {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table>
|
<table v-if="channel !== 'nightly' || nightlyRelease?.assets.length">
|
||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -239,14 +258,14 @@ function renderUrlTmpl(url_tmpl: string): string {
|
|||||||
<td> {{ pkg.arch }} </td>
|
<td> {{ pkg.arch }} </td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<a v-for="(url_tmpl, format) in pkg.gui_pkg_tmpl" class="download-link-span" :href="renderUrlTmpl(url_tmpl)">
|
<a v-for="link in renderLinks(pkg.gui_pkg_tmpl)" :key="link.format" class="download-link-span" :href="link.url">
|
||||||
{{format}}
|
{{link.format}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<a v-for="(url_tmpl, format) in pkg.cli_pkg_tmpl" class="download-link-span" :href="renderUrlTmpl(url_tmpl)">
|
<a v-for="link in renderLinks(pkg.cli_pkg_tmpl)" :key="link.format" class="download-link-span" :href="link.url">
|
||||||
{{format}}
|
{{link.format}}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ export default {
|
|||||||
load() {
|
load() {
|
||||||
return {
|
return {
|
||||||
easytier_latest_version: '2.6.4',
|
easytier_latest_version: '2.6.4',
|
||||||
easytier_pre_release_version: '2.6.3',
|
easytier_pre_release_version: '2.7.0',
|
||||||
github_accels: [
|
github_accels: [
|
||||||
'https://ghfast.top/',
|
'https://ghfast.top/',
|
||||||
'https://v6.gh-proxy.org/',
|
'https://v6.gh-proxy.org/',
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
export interface Release {
|
||||||
|
tag_name: string
|
||||||
|
prerelease?: boolean
|
||||||
|
draft?: boolean
|
||||||
|
assets: Array<{ name: string, browser_download_url: string }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findPrerelease(releases: Release[]): Release | null {
|
||||||
|
return releases.find(release => release.prerelease && !release.draft && release.tag_name !== 'nightly') ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveDownloadUrl(template: string, release: Release | null, fallbackVersion?: string): string | undefined {
|
||||||
|
if (release) {
|
||||||
|
const filename = template.slice(template.lastIndexOf('/') + 1)
|
||||||
|
const pattern = filename.split('{}')
|
||||||
|
.map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
||||||
|
.join('[^/]+')
|
||||||
|
return release.assets.find(asset => new RegExp(`^${pattern}$`).test(asset.name))?.browser_download_url
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackVersion ? template.replace(/\{\}/g, fallbackVersion) : undefined
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import type { Release } from '../releaseUtils.ts'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
// eslint-disable-next-line test/no-import-node-test -- Use the built-in runner without adding a test framework.
|
||||||
|
import { test } from 'node:test'
|
||||||
|
import { findPrerelease, resolveDownloadUrl } from '../releaseUtils.ts'
|
||||||
|
|
||||||
|
const cliTemplate = 'https://github.com/EasyTier/EasyTier/releases/download/v{}/easytier-linux-x86_64-v{}.zip'
|
||||||
|
const guiTemplate = 'https://github.com/EasyTier/EasyTier/releases/download/v{}/easytier-gui_{}_x64-setup.exe'
|
||||||
|
|
||||||
|
function release(tag_name: string, assets: string[] = [], prerelease = true): Release {
|
||||||
|
return {
|
||||||
|
tag_name,
|
||||||
|
prerelease,
|
||||||
|
assets: assets.map(name => ({ name, browser_download_url: `https://github.com/EasyTier/EasyTier/releases/download/${tag_name}/${name}` })),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('ordinary prereleases exclude rolling nightly and draft releases', () => {
|
||||||
|
const prerelease = release('v2.7.0')
|
||||||
|
assert.equal(findPrerelease([
|
||||||
|
release('nightly'),
|
||||||
|
{ ...release('v2.8.0'), draft: true },
|
||||||
|
prerelease,
|
||||||
|
release('v2.6.4', [], false),
|
||||||
|
]), prerelease)
|
||||||
|
assert.equal(findPrerelease([release('nightly'), release('v2.6.4', [], false)]), null)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('nightly uses the actual release tag and versioned asset name', () => {
|
||||||
|
const nightly = release('nightly', ['easytier-linux-x86_64-v2.7.0.zip'])
|
||||||
|
assert.equal(resolveDownloadUrl(cliTemplate, nightly), 'https://github.com/EasyTier/EasyTier/releases/download/nightly/easytier-linux-x86_64-v2.7.0.zip')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('GUI asset versions can differ from the release version', () => {
|
||||||
|
const prerelease = release('v2.6.1', ['easytier-gui_2.6.0_x64-setup.exe'])
|
||||||
|
assert.equal(resolveDownloadUrl(guiTemplate, prerelease), 'https://github.com/EasyTier/EasyTier/releases/download/v2.6.1/easytier-gui_2.6.0_x64-setup.exe')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Android assets without a version placeholder also resolve', () => {
|
||||||
|
const nightly = release('nightly', ['app-arm64-release.apk'])
|
||||||
|
assert.equal(resolveDownloadUrl('https://github.com/EasyTier/EasyTier/releases/download/v{}/app-arm64-release.apk', nightly), 'https://github.com/EasyTier/EasyTier/releases/download/nightly/app-arm64-release.apk')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('missing assets do not produce invented download links', () => {
|
||||||
|
assert.equal(resolveDownloadUrl(cliTemplate, release('nightly', ['easytier-linux-aarch64-v2.7.0.zip'])), undefined)
|
||||||
|
assert.equal(resolveDownloadUrl(guiTemplate, release('v2.6.4'), '2.6.4'), undefined)
|
||||||
|
assert.equal(resolveDownloadUrl(cliTemplate, release('nightly', ['easytier-linux-x86_64-v2.7.0Xzip'])), undefined)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('API failure preserves stable and prerelease fallbacks without guessing nightly assets', () => {
|
||||||
|
assert.equal(resolveDownloadUrl(cliTemplate, null, '2.6.4'), 'https://github.com/EasyTier/EasyTier/releases/download/v2.6.4/easytier-linux-x86_64-v2.6.4.zip')
|
||||||
|
assert.equal(resolveDownloadUrl(guiTemplate, null, '2.7.0'), 'https://github.com/EasyTier/EasyTier/releases/download/v2.7.0/easytier-gui_2.7.0_x64-setup.exe')
|
||||||
|
assert.equal(resolveDownloadUrl(cliTemplate, null), undefined)
|
||||||
|
})
|
||||||
+30
-28
@@ -1,40 +1,42 @@
|
|||||||
import { onMounted, ref } from 'vue'
|
import type { Release } from './releaseUtils'
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { findPrerelease } from './releaseUtils'
|
||||||
|
|
||||||
export function useLatestVersion() {
|
export function useLatestVersion() {
|
||||||
const latestVersion = ref<string | null>(null)
|
const latestRelease = ref<Release | null>(null)
|
||||||
const prereleaseVersion = ref<string | null>(null)
|
const prereleaseRelease = ref<Release | null>(null)
|
||||||
|
const nightlyRelease = ref<Release | null>(null)
|
||||||
|
const latestVersion = computed(() => latestRelease.value?.tag_name.replace(/^v/, '') ?? null)
|
||||||
|
const prereleaseVersion = computed(() => prereleaseRelease.value?.tag_name.replace(/^v/, '') ?? null)
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
async function fetchRelease<T>(path: string): Promise<T> {
|
||||||
const [latestRes, releasesRes] = await Promise.all([
|
const response = await fetch(`https://api.github.com/repos/EasyTier/EasyTier/releases${path}`, { signal: AbortSignal.timeout(10000) })
|
||||||
fetch('https://api.github.com/repos/EasyTier/EasyTier/releases/latest'),
|
if (!response.ok)
|
||||||
fetch('https://api.github.com/repos/EasyTier/EasyTier/releases?per_page=5'),
|
|
||||||
])
|
|
||||||
|
|
||||||
if (!latestRes.ok || !releasesRes.ok) {
|
|
||||||
throw new Error('Failed to fetch releases from GitHub API')
|
throw new Error('Failed to fetch releases from GitHub API')
|
||||||
}
|
return response.json()
|
||||||
|
|
||||||
const latestData = await latestRes.json() as { tag_name?: string }
|
|
||||||
const releases = await releasesRes.json() as Array<{ tag_name?: string, prerelease?: boolean }>
|
|
||||||
|
|
||||||
latestVersion.value = latestData.tag_name ?? null
|
|
||||||
prereleaseVersion.value = releases.find(item => item.prerelease)?.tag_name ?? null
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
error.value = err instanceof Error ? err.message : 'Unknown error'
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (latestVersion.value?.startsWith('v'))
|
const [latest, releases, nightly] = await Promise.allSettled([
|
||||||
latestVersion.value = latestVersion.value.slice(1)
|
fetchRelease<Release>('/latest'),
|
||||||
if (prereleaseVersion.value?.startsWith('v'))
|
fetchRelease<Release[]>('?per_page=100'),
|
||||||
prereleaseVersion.value = prereleaseVersion.value.slice(1)
|
fetchRelease<Release>('/tags/nightly'),
|
||||||
|
])
|
||||||
|
|
||||||
|
if (latest.status === 'fulfilled')
|
||||||
|
latestRelease.value = latest.value
|
||||||
|
if (releases.status === 'fulfilled')
|
||||||
|
prereleaseRelease.value = findPrerelease(releases.value)
|
||||||
|
if (nightly.status === 'fulfilled')
|
||||||
|
nightlyRelease.value = nightly.value
|
||||||
|
|
||||||
|
const failure = [latest, releases, nightly].find(result => result.status === 'rejected')
|
||||||
|
if (failure?.status === 'rejected')
|
||||||
|
error.value = failure.reason instanceof Error ? failure.reason.message : 'Unknown error'
|
||||||
|
loading.value = false
|
||||||
})
|
})
|
||||||
|
|
||||||
return { latestVersion, prereleaseVersion, loading, error }
|
return { latestVersion, prereleaseVersion, latestRelease, prereleaseRelease, nightlyRelease, loading, error }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user