Compare commits

...
Author SHA1 Message Date
Tunglies fc0d8fa2e5 chore(dev): reject mismatched Service and SDK versions 2026-11-15 22:27:28 +08:00
Tunglies b2689b4220 fix(ci): recognize diff as a system binary 2026-11-15 11:57:01 +08:00
github-actions[bot]andgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 5321eb44b8 chore: sync Mihomo changelog to v1.19.34 (#8651)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-11-15 01:52:23 +00:00
renovate[bot]andrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com> f0dd12dfb8 chore(deps): update rust crate warp to 0.4.4 (#8650)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-11-15 01:51:07 +00:00
Tunglies 423b51e780 ci: restore automated Mihomo changelog sync 2026-11-15 09:51:18 +08:00
7 changed files with 276 additions and 23 deletions
+113
View File
@@ -0,0 +1,113 @@
name: Sync Mihomo Changelog
on:
workflow_dispatch:
inputs:
dry_run:
description: Preview the Changelog diff without creating a PR
type: boolean
default: true
schedule:
# UTC+8 Monday 11:30
- cron: '30 3 * * 1'
permissions:
contents: write
pull-requests: write
issues: write
concurrency:
group: sync-mihomo-changelog
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.event.repository.default_branch }}
persist-credentials: false
- uses: actions/setup-node@v7
with:
node-version: '26.13.1'
- name: Sync Mihomo version
id: sync
env:
DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }}
run: |
args=()
if [[ "$DRY_RUN" == 'true' ]]; then args+=(--dry-run); fi
node scripts/sync-mihomo-version.mjs "${args[@]}"
- name: Create labeled PR and enqueue
if: steps.sync.outputs.changed == 'true' && !(github.event_name == 'workflow_dispatch' && inputs.dry_run)
uses: actions/github-script@v9
env:
MIHOMO_VERSION: ${{ steps.sync.outputs.version }}
with:
script: |
const { readFileSync } = await import('node:fs');
const { execFileSync } = await import('node:child_process');
const { owner, repo } = context.repo;
const base = context.payload.repository.default_branch;
const version = process.env.MIHOMO_VERSION;
const appVersion = JSON.parse(readFileSync('package.json', 'utf8')).version;
const branch = `chore/sync-mihomo-${appVersion}-${version}`;
const title = `chore: sync Mihomo changelog to ${version}`;
const pulls = await github.rest.pulls.list({
owner, repo, base, head: `${owner}:${branch}`, state: 'all',
});
let pr = pulls.data[0];
if (pr && (pr.state !== 'open' || pr.user.login !== 'github-actions[bot]')) {
throw new Error(`Existing candidate needs maintainer attention: ${pr.html_url}`);
}
if (!pr) {
const sha = execFileSync('git', ['rev-parse', 'HEAD'], { encoding: 'utf8' }).trim();
await github.rest.git.createRef({ owner, repo, ref: `refs/heads/${branch}`, sha });
await github.graphql(`mutation($input: CreateCommitOnBranchInput!) {
createCommitOnBranch(input: $input) { commit { oid } }
}`, {
input: {
branch: { repositoryNameWithOwner: `${owner}/${repo}`, branchName: branch },
expectedHeadOid: sha,
message: { headline: title },
fileChanges: { additions: [{
path: 'Changelog.md',
contents: readFileSync('Changelog.md').toString('base64'),
}] },
},
});
({ data: pr } = await github.rest.pulls.create({
owner, repo, base, head: branch, title,
body: `## Problem\n\nChangelog.md needs to record the latest stable Mihomo version.\n\n` +
`## Approach\n\nRead the same upstream version.txt used by the core download script.\n\n` +
`## Scope\n\nOnly the Mihomo version line in Changelog.md changes to ${version}.`,
}));
}
for (let attempt = 0; attempt < 10; attempt++) {
({ data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: pr.number }));
if (pr.mergeable !== null) break;
await new Promise(resolve => setTimeout(resolve, 2000));
}
if (!pr.mergeable) throw new Error(`Sync PR is not mergeable: ${pr.html_url}`);
const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number: pr.number,
});
if (files.length !== 1 || files[0].filename !== 'Changelog.md') {
throw new Error('The sync PR must change only Changelog.md.');
}
await github.rest.issues.addLabels({
owner, repo, issue_number: pr.number, labels: ['dependencies', 'upstream'],
});
const result = await github.graphql(`query($id: ID!) {
node(id: $id) { ... on PullRequest { mergeQueueEntry { id } } }
}`, { id: pr.node_id });
if (!result.node.mergeQueueEntry) {
await github.graphql(`mutation($input: EnqueuePullRequestInput!) {
enqueuePullRequest(input: $input) { mergeQueueEntry { id } }
}`, { input: { pullRequestId: pr.node_id, expectedHeadOid: pr.head.sha } });
}
await core.summary.addRaw(`Queued Mihomo sync PR: ${pr.html_url}\n`).write();
Generated
+20 -20
View File
@@ -1328,7 +1328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -2043,7 +2043,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users 0.5.2",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -2302,7 +2302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -2818,7 +2818,7 @@ dependencies = [
"gobject-sys 0.21.5",
"libc",
"system-deps 7.0.8",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -3372,7 +3372,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.61.2",
"windows-core 0.62.2",
]
[[package]]
@@ -4252,7 +4252,7 @@ dependencies = [
"png",
"serde",
"thiserror 2.0.20",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -4419,7 +4419,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -4896,7 +4896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
dependencies = [
"libc",
"windows-sys 0.48.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -5576,7 +5576,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -6129,7 +6129,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys 0.12.1",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -6188,7 +6188,7 @@ dependencies = [
"security-framework",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -6808,7 +6808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
dependencies = [
"libc",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -7867,7 +7867,7 @@ dependencies = [
"getrandom 0.4.3",
"once_cell",
"rustix 1.1.4",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -8533,7 +8533,7 @@ dependencies = [
"png",
"serde",
"thiserror 2.0.20",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -8642,7 +8642,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [
"memoffset",
"tempfile",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
@@ -8820,9 +8820,9 @@ dependencies = [
[[package]]
name = "warp"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0a808122a8a77eecdabaefd88ddb1913c4be5ea1465399f63ba64c7aa705fea"
checksum = "c92be475cc42b6b3913eeac77f0cbc0dd8f6a1ad6400c0722dbe36ba0c3ee799"
dependencies = [
"bytes",
"futures-channel",
@@ -9184,7 +9184,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.61.2",
]
[[package]]
@@ -9205,7 +9205,7 @@ dependencies = [
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
"windows-version",
]
@@ -9780,7 +9780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
dependencies = [
"cfg-if",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
]
[[package]]
+2
View File
@@ -23,6 +23,8 @@
GitHub, so they never reach users. -->
## v2.6.0
- **Mihomo 内核升级至 v1.19.34**
<details>
<summary><strong> 🐞 修复问题 </strong></summary>
+1 -1
View File
@@ -14,7 +14,7 @@
"duplicates",
"cycles"
],
"ignoreBinaries": ["rustc"],
"ignoreBinaries": ["diff", "rustc"],
"ignoreDependencies": ["lint-staged"],
"ignoreIssues": {
"src/types/generated/**": ["exports", "types"],
+50
View File
@@ -46,8 +46,58 @@ function run(command, args, options = {}) {
})
}
async function checkDevelopmentServiceVersion() {
const [guiOutput, daemonOutput] = await Promise.all([
run(
'cargo',
[
'metadata',
'--locked',
'--format-version=1',
'--manifest-path',
join(repositoryRoot, 'Cargo.toml'),
],
{ stdio: ['inherit', 'pipe', 'inherit'] },
),
run(
'cargo',
[
'metadata',
'--locked',
'--no-deps',
'--format-version=1',
'--manifest-path',
serviceManifest,
],
{ stdio: ['inherit', 'pipe', 'inherit'] },
),
])
const gui = JSON.parse(guiOutput)
const daemon = JSON.parse(daemonOutput).packages.find(
(pkg) => resolve(pkg.manifest_path) === serviceManifest,
)
const app = gui.packages.find(
(pkg) =>
resolve(pkg.manifest_path) ===
join(repositoryRoot, 'src-tauri', 'Cargo.toml'),
)
const dependency = gui.resolve?.nodes
.find((node) => node.id === app?.id)
?.deps.find((dep) => dep.name === 'clash_verge_service_ipc')
const sdk = gui.packages.find((pkg) => pkg.id === dependency?.pkg)
if (!daemon || !sdk)
throw new Error('Cargo did not resolve the development Service and GUI SDK')
if (daemon.version !== sdk.version) {
throw new Error(
`Development Service ${daemon.version} does not match the resolved GUI SDK ${sdk.version} (${sdk.manifest_path}). ` +
'Align the GUI dependency explicitly before starting development. Building the sibling daemon does not update the SDK.',
)
}
}
export async function prepareDevelopmentService() {
await access(serviceManifest)
await checkDevelopmentServiceVersion()
const output = await run(
'cargo',
[
+88
View File
@@ -0,0 +1,88 @@
import { spawnSync } from 'node:child_process'
import { appendFileSync, readFileSync, writeFileSync } from 'node:fs'
import { parseArgs } from 'node:util'
const { values } = parseArgs({
options: {
'dry-run': { type: 'boolean', default: false },
check: { type: 'boolean', default: false },
version: { type: 'string' },
file: { type: 'string', default: 'Changelog.md' },
},
})
async function main() {
let version = values.version
if (!version) {
const response = await fetch(
'https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt',
{ signal: AbortSignal.timeout(30_000) },
)
if (!response.ok)
throw new Error(`Failed to fetch Mihomo version: ${response.status}`)
version = await response.text()
}
version = version.trim().replace(/^v?/, 'v')
if (!/^v\d+\.\d+\.\d+$/.test(version))
throw new Error(`Invalid stable Mihomo version: ${version}`)
const content = readFileSync(values.file, 'utf8')
const title = /^## .+$/m.exec(content)
if (!title) throw new Error('Could not find changelog title.')
const start = title.index + title[0].length
const end = content.indexOf('\n## ', start)
const section = content.slice(start, end === -1 ? undefined : end)
const line =
/^(\s*-\s*(?:\*\*)?\s*Mihomo(?:\(Meta\))?\s*内核升级至\s*)v?\d+(?:\.\d+)+(?:[-+][^\s*]+)?((?:\*\*)?[\t ]*)$/m
const nextSection = line.test(section)
? section.replace(line, `$1${version}$2`)
: `\n\n- **Mihomo 内核升级至 ${version}**${section.replace(/^\n*/, '\n\n')}`
const nextContent =
content.slice(0, start) +
nextSection +
(end === -1 ? '' : content.slice(end))
const changed = content !== nextContent
if (process.env.GITHUB_OUTPUT)
appendFileSync(
process.env.GITHUB_OUTPUT,
`version=${version}\nchanged=${changed}\n`,
)
if (!changed) {
console.log(`Mihomo version in changelog is already ${version}`)
return
}
const diff = spawnSync(
'diff',
[
'-u',
'--label',
`a/${values.file}`,
'--label',
`b/${values.file}`,
values.file,
'-',
],
{ input: nextContent, encoding: 'utf8' },
)
if (diff.error) throw diff.error
if (diff.status !== 1)
throw new Error(diff.stderr || 'Could not preview changelog diff.')
process.stdout.write(diff.stdout)
if (process.env.GITHUB_STEP_SUMMARY)
appendFileSync(
process.env.GITHUB_STEP_SUMMARY,
`### Mihomo ${version}\n\n\`\`\`diff\n${diff.stdout}\`\`\`\n`,
)
if (values.check) {
process.exitCode = 1
return
}
if (!values['dry-run']) writeFileSync(values.file, nextContent)
}
main().catch((error) => {
console.error('sync-mihomo-version failed:', error.message)
process.exitCode = 1
})
+2 -2
View File
@@ -56,7 +56,7 @@ serde_json = { workspace = true }
serde_yaml_ng = { workspace = true }
smartstring = { workspace = true, features = ["serde"] }
socket2 = { workspace = true }
warp = { version = "0.4.3", features = ["server"] }
warp = { version = "0.4.4", features = ["server"] }
open = "5.4.5"
rfd = { version = "0.18.0", default-features = false, features = ["common-controls-v6", "xdg-portal"] }
dirs = "7.0.0"
@@ -153,7 +153,7 @@ tauri-plugin-updater = "2.14.1"
[dev-dependencies]
tokio = { workspace = true, features = ["test-util"] }
warp = { version = "0.4.3", features = ["test"] }
warp = { version = "0.4.4", features = ["test"] }
[lints]
workspace = true