fix(updater): show real app version and release notes
This commit is contained in:
parent
724813c72a
commit
01c4b744ef
|
|
@ -113,6 +113,25 @@ jobs:
|
|||
echo "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Generate release notes
|
||||
id: release-notes
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BODY="$(gh api "repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
|
||||
-f tag_name="${GITHUB_REF_NAME}" \
|
||||
--jq '.body')"
|
||||
if [ -z "$BODY" ]; then
|
||||
BODY="DBX ${GITHUB_REF_NAME}"
|
||||
fi
|
||||
DELIM="RELEASE_NOTES_$(date +%s%N)"
|
||||
{
|
||||
echo "body<<$DELIM"
|
||||
printf '%s\n' "$BODY"
|
||||
echo "$DELIM"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build Tauri app
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
|
|
@ -124,7 +143,7 @@ jobs:
|
|||
with:
|
||||
tagName: ${{ github.ref_name }}
|
||||
releaseName: 'DBX ${{ github.ref_name }}'
|
||||
releaseBody: 'See the assets below to download and install.'
|
||||
releaseBody: ${{ steps.release-notes.outputs.body }}
|
||||
releaseDraft: true
|
||||
prerelease: false
|
||||
args: --target ${{ matrix.target }}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const LATEST_JSON_URLS: &[&str] = &[
|
|||
"https://gh-proxy.org/https://github.com/t8y2/dbx/releases/latest/download/latest.json",
|
||||
"https://github.com/t8y2/dbx/releases/latest/download/latest.json",
|
||||
];
|
||||
const GITHUB_RELEASE_API_PREFIX: &str = "https://api.github.com/repos/t8y2/dbx/releases/tags/v";
|
||||
const RELEASE_URL_PREFIX: &str = "https://github.com/t8y2/dbx/releases/tag/v";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
@ -12,6 +13,15 @@ pub struct TauriRelease {
|
|||
pub version: String,
|
||||
#[serde(default)]
|
||||
pub notes: Option<String>,
|
||||
#[serde(skip)]
|
||||
pub github: Option<GithubReleaseMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct GithubReleaseMetadata {
|
||||
pub name: Option<String>,
|
||||
pub html_url: Option<String>,
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
|
|
@ -39,7 +49,12 @@ pub async fn fetch_latest_release() -> Result<TauriRelease, String> {
|
|||
.and_then(|r| r.error_for_status())
|
||||
{
|
||||
Ok(resp) => {
|
||||
return resp.json::<TauriRelease>().await.map_err(|e| format!("Failed to parse update response: {e}"));
|
||||
let mut release =
|
||||
resp.json::<TauriRelease>().await.map_err(|e| format!("Failed to parse update response: {e}"))?;
|
||||
if let Ok(github) = fetch_github_release_metadata(&client, &release.version).await {
|
||||
release.github = Some(github);
|
||||
}
|
||||
return Ok(release);
|
||||
}
|
||||
Err(e) => {
|
||||
last_err = format!("{e}");
|
||||
|
|
@ -49,19 +64,61 @@ pub async fn fetch_latest_release() -> Result<TauriRelease, String> {
|
|||
Err(format!("Failed to check updates: {last_err}"))
|
||||
}
|
||||
|
||||
async fn fetch_github_release_metadata(
|
||||
client: &reqwest::Client,
|
||||
version: &str,
|
||||
) -> Result<GithubReleaseMetadata, String> {
|
||||
let url = format!("{GITHUB_RELEASE_API_PREFIX}{}", normalize_version(version));
|
||||
client
|
||||
.get(url)
|
||||
.header(reqwest::header::USER_AGENT, "dbx-update-checker")
|
||||
.send()
|
||||
.await
|
||||
.and_then(|r| r.error_for_status())
|
||||
.map_err(|e| format!("{e}"))?
|
||||
.json::<GithubReleaseMetadata>()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to parse GitHub release response: {e}"))
|
||||
}
|
||||
|
||||
pub fn build_update_info(release: TauriRelease, current_version: &str) -> UpdateInfo {
|
||||
let latest_version = normalize_version(&release.version);
|
||||
let github = release.github.as_ref();
|
||||
let release_notes = github
|
||||
.and_then(|metadata| non_empty(metadata.body.as_deref()))
|
||||
.map(ToOwned::to_owned)
|
||||
.or(release.notes)
|
||||
.unwrap_or_default();
|
||||
let release_name = github
|
||||
.and_then(|metadata| non_empty(metadata.name.as_deref()))
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| format!("DBX v{latest_version}"));
|
||||
let release_url = github
|
||||
.and_then(|metadata| non_empty(metadata.html_url.as_deref()))
|
||||
.map(ToOwned::to_owned)
|
||||
.unwrap_or_else(|| format!("{RELEASE_URL_PREFIX}{latest_version}"));
|
||||
|
||||
UpdateInfo {
|
||||
update_available: is_newer_version(&latest_version, current_version),
|
||||
current_version: current_version.to_string(),
|
||||
release_name: format!("DBX v{latest_version}"),
|
||||
release_url: format!("{RELEASE_URL_PREFIX}{latest_version}"),
|
||||
release_notes: release.notes.unwrap_or_default(),
|
||||
release_name,
|
||||
release_url,
|
||||
release_notes,
|
||||
latest_version,
|
||||
}
|
||||
}
|
||||
|
||||
fn non_empty(value: Option<&str>) -> Option<&str> {
|
||||
value.and_then(|value| {
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalize_version(version: &str) -> String {
|
||||
version.trim().trim_start_matches('v').to_string()
|
||||
}
|
||||
|
|
@ -91,7 +148,7 @@ pub fn is_newer_version(latest: &str, current: &str) -> bool {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{is_newer_version, normalize_version};
|
||||
use super::{build_update_info, is_newer_version, normalize_version, GithubReleaseMetadata, TauriRelease};
|
||||
|
||||
#[test]
|
||||
fn normalizes_tag_versions() {
|
||||
|
|
@ -106,4 +163,23 @@ mod tests {
|
|||
assert!(!is_newer_version("0.2.0", "0.2.0"));
|
||||
assert!(!is_newer_version("0.1.9", "0.2.0"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_info_prefers_github_release_metadata() {
|
||||
let release = TauriRelease {
|
||||
version: "0.5.3".to_string(),
|
||||
notes: Some("See the assets below to download and install.".to_string()),
|
||||
github: Some(GithubReleaseMetadata {
|
||||
name: Some("DBX v0.5.3".to_string()),
|
||||
html_url: Some("https://github.com/t8y2/dbx/releases/tag/v0.5.3".to_string()),
|
||||
body: Some("### 新功能\n\n真实发布说明".to_string()),
|
||||
}),
|
||||
};
|
||||
|
||||
let info = build_update_info(release, "0.5.2");
|
||||
|
||||
assert_eq!(info.release_name, "DBX v0.5.3");
|
||||
assert_eq!(info.release_url, "https://github.com/t8y2/dbx/releases/tag/v0.5.3");
|
||||
assert_eq!(info.release_notes, "### 新功能\n\n真实发布说明");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -701,6 +701,7 @@ onUnmounted(() => {
|
|||
<AppDialogs
|
||||
:show-connection-dialog="showConnectionDialog"
|
||||
:show-settings-dialog="showSettingsDialog"
|
||||
:app-version="appVersion"
|
||||
:show-danger-dialog="showDangerDialog"
|
||||
:danger-sql="dangerSql"
|
||||
@update:show-connection-dialog="showConnectionDialog = $event"
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const { toast } = useToast();
|
|||
const props = defineProps<{
|
||||
open: boolean;
|
||||
initialTab?: string;
|
||||
appVersion?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
@ -113,6 +114,7 @@ function setAppLayout(value: "separated" | "classic") {
|
|||
|
||||
const activeSettingsTab = ref("editor");
|
||||
const isWeb = !isTauriRuntime();
|
||||
const displayedAppVersion = computed(() => (props.appVersion ? `v${props.appVersion}` : ""));
|
||||
|
||||
function openExternalUrl(url: string) {
|
||||
if (isTauriRuntime()) {
|
||||
|
|
@ -933,7 +935,12 @@ watch(
|
|||
<div class="text-lg font-semibold">DBX</div>
|
||||
<p class="text-sm text-muted-foreground">{{ t("settings.aboutDescription") }}</p>
|
||||
</div>
|
||||
<div class="rounded-md border bg-background px-2 py-1 text-xs text-muted-foreground">v0.5.0</div>
|
||||
<div
|
||||
v-if="displayedAppVersion"
|
||||
class="rounded-md border bg-background px-2 py-1 text-xs text-muted-foreground"
|
||||
>
|
||||
{{ displayedAppVersion }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ const props = defineProps<{
|
|||
showConnectionDialog: boolean;
|
||||
showSettingsDialog: boolean;
|
||||
settingsInitialTab?: string;
|
||||
appVersion?: string;
|
||||
showDangerDialog: boolean;
|
||||
dangerSql: string;
|
||||
}>();
|
||||
|
|
@ -102,6 +103,7 @@ watch(
|
|||
<EditorSettingsDialog
|
||||
:open="showSettingsDialog"
|
||||
:initial-tab="settingsInitialTab || 'editor'"
|
||||
:app-version="appVersion"
|
||||
@update:open="emit('update:showSettingsDialog', $event)"
|
||||
/>
|
||||
<DangerConfirmDialog
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { strict as assert } from "node:assert";
|
||||
import test from "node:test";
|
||||
|
||||
test("settings about panel uses the app version prop instead of a hard-coded version", () => {
|
||||
const source = readFileSync("src/components/editor/EditorSettingsDialog.vue", "utf8");
|
||||
|
||||
assert.equal(source.includes("v0.5.0"), false);
|
||||
assert.match(source, /appVersion/);
|
||||
});
|
||||
|
||||
test("release workflow does not publish the default Tauri release body", () => {
|
||||
const source = readFileSync(".github/workflows/release.yml", "utf8");
|
||||
|
||||
assert.equal(source.includes("See the assets below to download and install."), false);
|
||||
});
|
||||
Loading…
Reference in New Issue