Skip to content

馃敄 chore(release): Bump version to v0.5.6 #48

馃敄 chore(release): Bump version to v0.5.6

馃敄 chore(release): Bump version to v0.5.6 #48

Workflow file for this run

name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
env:
SING_BOX_VERSION: "1.13.13"
jobs:
build:
name: Build ${{ matrix.asset }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
binary: v2raydar.exe
asset: v2raydar-windows-x86_64.exe
embedded_asset: v2raydar-windows-x86_64_with_singbox.zip
embedded_format: zip
embedded_binary: v2raydar.exe
sing_box_platform: windows
sing_box_arch: amd64
sing_box_binary: sing-box.exe
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
binary: v2raydar
asset: v2raydar-linux-x86_64
embedded_asset: v2raydar-linux-x86_64_with_singbox.tar.gz
embedded_format: tar.gz
embedded_binary: v2raydar
sing_box_platform: linux
sing_box_arch: amd64
sing_box_binary: sing-box
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Cargo build state
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/${{ matrix.target }}
key: cargo-build-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-build-${{ runner.os }}-${{ matrix.target }}-
- name: Install Rust target
shell: bash
run: |
rustup default stable
rustup target add "${{ matrix.target }}"
- name: Build release binary
run: cargo build --release --locked --target "${{ matrix.target }}"
- name: Stage executable
shell: pwsh
run: |
New-Item -ItemType Directory -Force dist | Out-Null
$source = Join-Path "target/${{ matrix.target }}/release" "${{ matrix.binary }}"
$destination = Join-Path "dist" "${{ matrix.asset }}"
Copy-Item -LiteralPath $source -Destination $destination
- name: Upload executable artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset }}
path: dist/${{ matrix.asset }}
if-no-files-found: error
- name: Stage embedded sing-box package
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$ErrorActionPreference = "Stop"
$headers = @{ "User-Agent" = "github-actions" }
# Inject the token into the headers if it exists
if ([bool]$env:GITHUB_TOKEN) {
$headers["Authorization"] = "Bearer $($env:GITHUB_TOKEN)"
}
$version = "${{ env.SING_BOX_VERSION }}"
$release = Invoke-RestMethod -Headers $headers -Uri "https://api.github.com/repos/SagerNet/sing-box/releases/tags/v$version"
function Test-NameToken([string]$Name, [string]$Token) {
return $Name -match ('(^|[-_.])' + [regex]::Escape($Token) + '($|[-_.])')
}
$asset = $release.assets |
Where-Object {
$name = $_.name.ToLowerInvariant()
$name -like "*${{ matrix.sing_box_platform }}*" -and
(Test-NameToken $name "${{ matrix.sing_box_arch }}") -and
($name.EndsWith(".zip") -or $name.EndsWith(".tar.gz") -or $name.EndsWith(".tgz"))
} |
Select-Object -First 1
if (-not $asset) {
throw "No sing-box v$version asset found for ${{ matrix.sing_box_platform }}-${{ matrix.sing_box_arch }}"
}
$download = Join-Path "dist" $asset.name
Invoke-WebRequest -Headers $headers -Uri $asset.browser_download_url -OutFile $download
$extractRoot = Join-Path "dist" "sing-box-$version-${{ matrix.sing_box_platform }}-${{ matrix.sing_box_arch }}"
New-Item -ItemType Directory -Force $extractRoot | Out-Null
if ($asset.name.ToLowerInvariant().EndsWith(".zip")) {
Expand-Archive -LiteralPath $download -DestinationPath $extractRoot -Force
} else {
tar -xf $download -C $extractRoot
}
$singBox = Get-ChildItem -LiteralPath $extractRoot -Recurse -File -Filter "${{ matrix.sing_box_binary }}" |
Select-Object -First 1
if (-not $singBox) {
throw "sing-box executable was not found after extracting $($asset.name)"
}
& $singBox.FullName version
$packageRoot = Join-Path "dist" "package-${{ matrix.embedded_asset }}"
New-Item -ItemType Directory -Force $packageRoot | Out-Null
Copy-Item -LiteralPath (Join-Path "dist" "${{ matrix.asset }}") -Destination (Join-Path $packageRoot "${{ matrix.embedded_binary }}")
Copy-Item -LiteralPath $singBox.FullName -Destination (Join-Path $packageRoot "${{ matrix.sing_box_binary }}")
if ("${{ runner.os }}" -ne "Windows") {
chmod +x (Join-Path $packageRoot "${{ matrix.embedded_binary }}")
chmod +x (Join-Path $packageRoot "${{ matrix.sing_box_binary }}")
}
if ("${{ matrix.embedded_format }}" -eq "zip") {
Compress-Archive -Path (Join-Path $packageRoot "*") -DestinationPath (Join-Path "dist" "${{ matrix.embedded_asset }}") -Force
} else {
tar -C $packageRoot -czf (Join-Path "dist" "${{ matrix.embedded_asset }}") .
}
- name: Upload embedded sing-box artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.embedded_asset }}
path: dist/${{ matrix.embedded_asset }}
if-no-files-found: error
build-macos:
name: Build v2raydar-macos-universal.app.zip
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Cargo build state
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/x86_64-apple-darwin
target/aarch64-apple-darwin
key: cargo-build-${{ runner.os }}-macos-universal-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-build-${{ runner.os }}-macos-universal-
- name: Install Rust targets
shell: bash
run: |
rustup default stable
rustup target add x86_64-apple-darwin aarch64-apple-darwin
- name: Build release binaries
shell: bash
run: |
cargo build --release --locked --target x86_64-apple-darwin
cargo build --release --locked --target aarch64-apple-darwin
- name: Stage universal app bundle
shell: bash
run: |
set -euo pipefail
asset="v2raydar-macos-universal.app.zip"
app="dist/V2RayDAR.app"
version="$(awk -F '"' '/^version = / { print $2; exit }' Cargo.toml)"
mkdir -p "$app/Contents/MacOS" "$app/Contents/Resources"
lipo -create \
-output "$app/Contents/MacOS/v2raydar-bin" \
"target/x86_64-apple-darwin/release/v2raydar" \
"target/aarch64-apple-darwin/release/v2raydar"
chmod +x "$app/Contents/MacOS/v2raydar-bin"
lipo -info "$app/Contents/MacOS/v2raydar-bin"
cat > "$app/Contents/MacOS/V2RayDAR" <<'EOF'
#!/bin/sh
set -eu
dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
app="$dir/v2raydar-bin"
if [ -t 1 ]; then
exec "$app" "$@"
fi
APP_PATH="$app" osascript <<'APPLESCRIPT'
set appPath to system attribute "APP_PATH"
tell application "Terminal"
activate
do script quoted form of appPath
end tell
APPLESCRIPT
EOF
chmod +x "$app/Contents/MacOS/V2RayDAR"
cat > "$app/Contents/Info.plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>V2RayDAR</string>
<key>CFBundleIconFile</key>
<string>V2RayDAR</string>
<key>CFBundleIdentifier</key>
<string>app.v2raydar.V2RayDAR</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>V2RayDAR</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${version}</string>
<key>CFBundleVersion</key>
<string>${GITHUB_RUN_NUMBER}</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
EOF
iconset="dist/V2RayDAR.iconset"
mkdir -p "$iconset"
sips -z 16 16 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_16x16.png" >/dev/null
sips -z 32 32 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_16x16@2x.png" >/dev/null
sips -z 32 32 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_32x32.png" >/dev/null
sips -z 64 64 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_32x32@2x.png" >/dev/null
sips -z 128 128 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_128x128.png" >/dev/null
sips -z 256 256 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_128x128@2x.png" >/dev/null
sips -z 256 256 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_256x256.png" >/dev/null
sips -z 512 512 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_256x256@2x.png" >/dev/null
sips -z 512 512 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_512x512.png" >/dev/null
sips -z 1024 1024 "assets/V2RayDAR_logo_v1.png" --out "$iconset/icon_512x512@2x.png" >/dev/null
iconutil -c icns "$iconset" -o "$app/Contents/Resources/V2RayDAR.icns"
ditto -c -k --sequesterRsrc --keepParent "$app" "dist/$asset"
- name: Upload app artifact
uses: actions/upload-artifact@v4
with:
name: v2raydar-macos-universal.app.zip
path: dist/v2raydar-macos-universal.app.zip
if-no-files-found: error
- name: Stage embedded sing-box app bundle
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
version="${SING_BOX_VERSION}"
embedded_asset="v2raydar-macos-universal_with_singbox.zip"
work="dist/sing-box-${version}-darwin"
mkdir -p "$work"
python3 <<'PY'
import json
import os
import re
import urllib.request
version = os.environ["SING_BOX_VERSION"]
github_token = os.environ.get("GITHUB_TOKEN")
work = os.path.join("dist", f"sing-box-{version}-darwin")
url = f"https://api.github.com/repos/SagerNet/sing-box/releases/tags/v{version}"
headers = {"User-Agent": "github-actions"}
# Inject the token into the headers if it exists
if github_token:
headers["Authorization"] = f"Bearer {github_token}"
req = urllib.request.Request(url, headers=headers)
release = json.load(urllib.request.urlopen(req))
def token(name, value):
return re.search(r"(^|[-_.])" + re.escape(value) + r"($|[-_.])", name) is not None
for arch in ("amd64", "arm64"):
for asset in release.get("assets", []):
name = asset["name"].lower()
if "darwin" in name and token(name, arch) and name.endswith((".tar.gz", ".tgz", ".zip")):
target = os.path.join(work, asset["name"])
# Create a request object for the download to pass headers here too
download_req = urllib.request.Request(asset["browser_download_url"], headers=headers)
with urllib.request.urlopen(download_req) as response, open(target, 'wb') as out_file:
out_file.write(response.read())
break
else:
raise SystemExit(f"No sing-box v{version} darwin-{arch} asset found")
PY
for archive in "$work"/*; do
mkdir -p "$work/extract/$(basename "$archive")"
case "$archive" in
*.zip) unzip -q "$archive" -d "$work/extract/$(basename "$archive")" ;;
*) tar -xf "$archive" -C "$work/extract/$(basename "$archive")" ;;
esac
done
amd64_bin="$(find "$work/extract" -path '*darwin-amd64*' -type f -name sing-box | head -n 1)"
arm64_bin="$(find "$work/extract" -path '*darwin-arm64*' -type f -name sing-box | head -n 1)"
test -n "$amd64_bin"
test -n "$arm64_bin"
lipo -create -output "dist/V2RayDAR.app/Contents/MacOS/sing-box" "$amd64_bin" "$arm64_bin"
chmod +x "dist/V2RayDAR.app/Contents/MacOS/sing-box"
"dist/V2RayDAR.app/Contents/MacOS/sing-box" version
ditto -c -k --sequesterRsrc --keepParent "dist/V2RayDAR.app" "dist/$embedded_asset"
- name: Upload embedded sing-box app artifact
uses: actions/upload-artifact@v4
with:
name: v2raydar-macos-universal_with_singbox.zip
path: dist/v2raydar-macos-universal_with_singbox.zip
if-no-files-found: error
build-termux:
name: Build ${{ matrix.asset }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-linux-android
clang_prefix: aarch64-linux-android
asset: v2raydar-termux-aarch64.tar.gz
package_dir: v2raydar-termux-aarch64
label: aarch64
- target: x86_64-linux-android
clang_prefix: x86_64-linux-android
asset: v2raydar-termux-x86_64.tar.gz
package_dir: v2raydar-termux-x86_64
label: x86_64
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Cargo build state
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/${{ matrix.target }}
key: cargo-build-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-build-${{ runner.os }}-${{ matrix.target }}-
- name: Install Rust target
shell: bash
run: |
rustup default stable
rustup target add "${{ matrix.target }}"
- name: Build release binary
shell: bash
env:
API_LEVEL: "24"
run: |
set -euo pipefail
ndk="${ANDROID_NDK_HOME:-${ANDROID_NDK_LATEST_HOME:-}}"
if [ -z "$ndk" ]; then
echo "ANDROID_NDK_HOME or ANDROID_NDK_LATEST_HOME is required" >&2
exit 1
fi
linker="${ndk}/toolchains/llvm/prebuilt/linux-x86_64/bin/${{ matrix.clang_prefix }}${API_LEVEL}-clang"
ar="${ndk}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar"
test -x "$linker"
test -x "$ar"
linker_var="CARGO_TARGET_$(echo "${{ matrix.target }}" | tr '[:lower:]-' '[:upper:]_')_LINKER"
cc_var="CC_$(echo "${{ matrix.target }}" | tr '-' '_')"
ar_var="AR_$(echo "${{ matrix.target }}" | tr '-' '_')"
export "$linker_var=$linker"
export "$cc_var=$linker"
export "$ar_var=$ar"
cargo build --release --locked --target "${{ matrix.target }}"
- name: Stage Termux package
shell: bash
run: |
set -euo pipefail
asset="${{ matrix.asset }}"
package="dist/${{ matrix.package_dir }}"
mkdir -p "$package"
cp target/${{ matrix.target }}/release/v2raydar "$package/v2raydar"
chmod +x "$package/v2raydar"
cat > "$package/install-termux.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/bash
cd "\$(dirname "\$0")"
echo "Installing sing-box..."
if ! pkg install -y sing-box=${SING_BOX_VERSION}; then
echo "鈿狅笍 sing-box=${SING_BOX_VERSION} not available, trying latest..."
pkg install -y sing-box || echo "鈿狅笍 Install sing-box manually later: pkg install sing-box"
fi
install -Dm755 v2raydar "\${PREFIX}/bin/v2raydar"
cat <<'MSG'
Installed V2RayDAR to \$PREFIX/bin/v2raydar.
Run with: v2raydar --no-tui
MSG
EOF
chmod +x "$package/install-termux.sh"
cat > "$package/README-termux.txt" <<EOF
V2RayDAR Termux ${{ matrix.label }} release
This package is built for ${{ matrix.label }} Android devices running Termux.
It does not include sing-box. Install the pinned Termux package:
pkg install sing-box=${SING_BOX_VERSION}
Quick install:
tar -xzf ${asset}
cd ${{ matrix.package_dir }}
./install-termux.sh
v2raydar --no-tui
EOF
tar -C dist -czf "dist/$asset" "${{ matrix.package_dir }}"
- name: Upload Termux artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset }}
path: dist/${{ matrix.asset }}
if-no-files-found: error
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache Cargo test state
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: cargo-test-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
cargo-test-${{ runner.os }}-
- name: Install Rust
shell: bash
run: |
rustup default stable
rustup component add rustfmt clippy
- name: Format check
run: cargo fmt --check
- name: Clippy
run: cargo clippy --locked --all-targets --all-features -- -D warnings
- name: Tests
run: cargo test --locked
publish:
name: Publish GitHub release
needs: [build, build-macos, build-termux, test]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.ref_name }}
REPOSITORY: ${{ github.repository }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download executable artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Generate SHA-256 checksums
shell: pwsh
run: |
$lines = Get-ChildItem -LiteralPath dist -File |
Sort-Object Name |
ForEach-Object {
$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $_.FullName).Hash.ToLowerInvariant()
"$hash $($_.Name)"
}
$lines | Set-Content -LiteralPath "dist/checksums.txt" -Encoding ascii
- name: Create or update release
shell: bash
run: |
git log -1 --format=%b > release-notes.txt
if gh release view "$TAG_NAME" --repo "$REPOSITORY" >/dev/null 2>&1; then
gh release edit "$TAG_NAME" --repo "$REPOSITORY" --notes-file release-notes.txt
gh release upload "$TAG_NAME" dist/* --clobber --repo "$REPOSITORY"
else
gh release create "$TAG_NAME" dist/* \
--repo "$REPOSITORY" \
--title "V2RayDAR $TAG_NAME" \
--notes-file release-notes.txt
fi