Skip to content

release

release #15

Workflow file for this run

name: release
on:
workflow_dispatch:
inputs:
release_tag:
description: "Release tag to publish, for example v0.3.7. Leave empty for artifact-only manual builds."
required: false
type: string
publish_release:
description: "Create/update the GitHub Release and Docker image. Requires release_tag."
required: false
default: false
type: boolean
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref_name || inputs.release_tag || github.run_id }}
cancel-in-progress: false
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
prepare:
name: Prepare release
runs-on: ubuntu-latest
outputs:
publish: ${{ steps.release.outputs.publish }}
tag: ${{ steps.release.outputs.tag }}
steps:
- name: Resolve release mode
id: release
shell: bash
run: |
publish="false"
tag=""
# push tag 触发 → 自动发布;手动触发 → 读取 inputs
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
publish="true"
tag="${GITHUB_REF_NAME}"
else
publish="${{ inputs.publish_release }}"
tag="${{ inputs.release_tag }}"
fi
# 发布时校验 tag 格式:v + 语义版本,允许 pre-release 后缀如 -rc1, +build123
if [[ "${publish}" == "true" ]]; then
if [[ ! "${tag}" =~ ^v[0-9]+(\.[0-9]+)*([-+][0-9A-Za-z.-]+)?$ ]]; then
echo "release_tag must look like v0.3.7 when publishing" >&2
exit 1
fi
fi
echo "publish=${publish}" >> "${GITHUB_OUTPUT}"
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
build-linux-server:
name: Build Server - ${{ matrix.platform.release_for }}
needs: prepare
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform:
- release_for: linux_x86_64_musl
target: x86_64-unknown-linux-musl
binary_name: nodeget-server-linux-x86_64-musl
- release_for: linux_x86_64_gnu
target: x86_64-unknown-linux-gnu
binary_name: nodeget-server-linux-x86_64-gnu
- release_for: linux_aarch64_gnu
target: aarch64-unknown-linux-gnu
binary_name: nodeget-server-linux-aarch64-gnu
- release_for: linux_aarch64_musl
target: aarch64-unknown-linux-musl
binary_name: nodeget-server-linux-aarch64-musl
- release_for: linux_armv7_gnueabihf
target: armv7-unknown-linux-gnueabihf
binary_name: nodeget-server-linux-armv7-gnueabihf
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
cache-shared-key: release-linux-${{ matrix.platform.target }}
- name: Install cross
env:
CROSS_VERSION: v0.2.5
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p "${HOME}/.local/bin"
gh release download "${CROSS_VERSION}" \
--repo cross-rs/cross \
--pattern cross-x86_64-unknown-linux-gnu.tar.gz \
-O - \
| tar -xz -C "${HOME}/.local/bin"
echo "${HOME}/.local/bin" >> "${GITHUB_PATH}"
- name: Build binary
run: cross build --package nodeget-server --target ${{ matrix.platform.target }} --profile minimal --jobs 32
env:
CROSS_NO_WARNINGS: 0
- name: Compress binary
run: upx -9 ./target/${{ matrix.platform.target }}/minimal/nodeget-server
- name: Rename binary
run: cp target/${{ matrix.platform.target }}/minimal/nodeget-server target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: server-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
if-no-files-found: error
retention-days: 14
build-linux-agent:
name: Build Agent - ${{ matrix.platform.release_for }}
needs: prepare
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform:
# ── x86_64 ──
- release_for: linux_x86_64_musl
target: x86_64-unknown-linux-musl
binary_name: nodeget-agent-linux-x86_64-musl
- release_for: linux_x86_64_gnu
target: x86_64-unknown-linux-gnu
binary_name: nodeget-agent-linux-x86_64-gnu
# ── i686 ──
- release_for: linux_i686_gnu
target: i686-unknown-linux-gnu
binary_name: nodeget-agent-linux-i686-gnu
- release_for: linux_i686_musl
target: i686-unknown-linux-musl
binary_name: nodeget-agent-linux-i686-musl
# ── aarch64 ──
- release_for: linux_aarch64_gnu
target: aarch64-unknown-linux-gnu
binary_name: nodeget-agent-linux-aarch64-gnu
- release_for: linux_aarch64_musl
target: aarch64-unknown-linux-musl
binary_name: nodeget-agent-linux-aarch64-musl
# ── arm (generic) ──
- release_for: linux_arm_gnueabi
target: arm-unknown-linux-gnueabi
binary_name: nodeget-agent-linux-arm-gnueabi
- release_for: linux_arm_gnueabihf
target: arm-unknown-linux-gnueabihf
binary_name: nodeget-agent-linux-arm-gnueabihf
- release_for: linux_arm_musleabi
target: arm-unknown-linux-musleabi
binary_name: nodeget-agent-linux-arm-musleabi
- release_for: linux_arm_musleabihf
target: arm-unknown-linux-musleabihf
binary_name: nodeget-agent-linux-arm-musleabihf
# Android:NDK 缺少 libunwind
- release_for: linux_arm_androideabi
target: arm-linux-androideabi
binary_name: nodeget-agent-linux-arm-androideabi
build_std: true
# ── armv7 ──
- release_for: linux_armv7_gnueabi
target: armv7-unknown-linux-gnueabi
binary_name: nodeget-agent-linux-armv7-gnueabi
- release_for: linux_armv7_gnueabihf
target: armv7-unknown-linux-gnueabihf
binary_name: nodeget-agent-linux-armv7-gnueabihf
- release_for: linux_armv7_musleabi
target: armv7-unknown-linux-musleabi
binary_name: nodeget-agent-linux-armv7-musleabi
- release_for: linux_armv7_musleabihf
target: armv7-unknown-linux-musleabihf
binary_name: nodeget-agent-linux-armv7-musleabihf
# Android:NDK 缺少 libunwind
- release_for: linux_armv7_androideabi
target: armv7-linux-androideabi
binary_name: nodeget-agent-linux-armv7-androideabi
build_std: true
# ── armv5te (tier 3):无预编译 std,必须 build-std ──
- release_for: linux_armv5te_gnueabi
target: armv5te-unknown-linux-gnueabi
binary_name: nodeget-agent-linux-armv5te-gnueabi
build_std: true
- release_for: linux_armv5te_musleabi
target: armv5te-unknown-linux-musleabi
binary_name: nodeget-agent-linux-armv5te-musleabi
build_std: true
# ── thumb ──
- release_for: linux_thumbv7neon_gnueabihf
target: thumbv7neon-unknown-linux-gnueabihf
binary_name: nodeget-agent-linux-thumbv7neon-gnueabihf
# Android:stable 无预编译 std,必须 nightly + build-std
- release_for: linux_thumbv7neon_androideabi
target: thumbv7neon-linux-androideabi
binary_name: nodeget-agent-linux-thumbv7neon-androideabi
build_std: true
# mips (tier 3):无预编译 std,必须 build-std
- release_for: linux_mips_gnu
target: mips-unknown-linux-gnu
binary_name: nodeget-agent-linux-mips-gnu
build_std: true
- release_for: linux_mips_musl
target: mips-unknown-linux-musl
binary_name: nodeget-agent-linux-mips-musl
build_std: true
# mipsel (tier 3)
- release_for: linux_mipsel_gnu
target: mipsel-unknown-linux-gnu
binary_name: nodeget-agent-linux-mipsel-gnu
build_std: true
- release_for: linux_mipsel_musl
target: mipsel-unknown-linux-musl
binary_name: nodeget-agent-linux-mipsel-musl
build_std: true
# mips64 (tier 3)
- release_for: linux_mips64_gnu
target: mips64-unknown-linux-gnuabi64
binary_name: nodeget-agent-linux-mips64-gnu
build_std: true
no_upx: true
- release_for: linux_mips64_musl
target: mips64-unknown-linux-muslabi64
binary_name: nodeget-agent-linux-mips64-musl
build_std: true
no_upx: true
# mips64el (tier 3)
- release_for: linux_mips64el_gnu
target: mips64el-unknown-linux-gnuabi64
binary_name: nodeget-agent-linux-mips64el-gnu
build_std: true
no_upx: true
- release_for: linux_mips64el_musl
target: mips64el-unknown-linux-muslabi64
binary_name: nodeget-agent-linux-mips64el-musl
build_std: true
no_upx: true
# powerpc
- release_for: linux_powerpc_gnu
target: powerpc-unknown-linux-gnu
binary_name: nodeget-agent-linux-powerpc-gnu
build_std: true
- release_for: linux_powerpc64_gnu
target: powerpc64-unknown-linux-gnu
binary_name: nodeget-agent-linux-powerpc64-gnu
no_upx: true
- release_for: linux_powerpc64le_gnu
target: powerpc64le-unknown-linux-gnu
binary_name: nodeget-agent-linux-powerpc64le-gnu
no_upx: true
# s390x (IBM Z)
- release_for: linux_s390x_gnu
target: s390x-unknown-linux-gnu
binary_name: nodeget-agent-linux-s390x-gnu
no_upx: true
# riscv64
- release_for: linux_riscv64gc_gnu
target: riscv64gc-unknown-linux-gnu
binary_name: nodeget-agent-linux-riscv64gc-gnu
no_upx: true
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
cache-shared-key: release-agent-linux-${{ matrix.platform.target }}
- name: Install cross
env:
CROSS_VERSION: v0.2.5
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p "${HOME}/.local/bin"
gh release download "${CROSS_VERSION}" \
--repo cross-rs/cross \
--pattern cross-x86_64-unknown-linux-gnu.tar.gz \
-O - \
| tar -xz -C "${HOME}/.local/bin"
echo "${HOME}/.local/bin" >> "${GITHUB_PATH}"
- name: Install nightly toolchain for build-std
if: ${{ matrix.platform.build_std }}
run: rustup install nightly && rustup component add rust-src --toolchain nightly
# 清除 CI 缓存中残留的预编译 target std,防止与 -Z build-std 冲突
# 产生 "duplicate lang item in crate 'core'" 错误
- name: Clean cached target std for build-std
if: ${{ matrix.platform.build_std }}
run: rustup target remove --toolchain nightly ${{ matrix.platform.target }} 2>/dev/null || true
- name: Build binary (stable)
if: ${{ !matrix.platform.build_std }}
run: cross build --package nodeget-agent --target ${{ matrix.platform.target }} --profile minimal --jobs 32
env:
CROSS_NO_WARNINGS: 0
# cross v0.2.5 的 Cross.toml build-std 只支持布尔值(true),
# 不支持字符串 "std,panic_abort",因此 -Z build-std=std,panic_abort
# 必须在命令行显式传递以包含 panic_abort。
# Cross.toml 中的 build-std = true 让 cross 跳过 rustup target add。
- name: Build binary (nightly, build-std)
if: ${{ matrix.platform.build_std }}
run: cross +nightly build --package nodeget-agent --target ${{ matrix.platform.target }} --profile minimal --jobs 32 -Z build-std=std,panic_abort
env:
CROSS_NO_WARNINGS: 0
- name: Compress binary
if: ${{ !matrix.platform.no_upx }}
run: upx -9 ./target/${{ matrix.platform.target }}/minimal/nodeget-agent
- name: Rename binary
run: cp target/${{ matrix.platform.target }}/minimal/nodeget-agent target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: agent-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
if-no-files-found: error
retention-days: 14
build-windows-server:
name: Build Server - ${{ matrix.platform.release_for }}
needs: prepare
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
platform:
- release_for: windows_x86_64
target: x86_64-pc-windows-msvc
binary_name: nodeget-server-windows-x86_64.exe
- release_for: windows_aarch64
target: aarch64-pc-windows-msvc
binary_name: nodeget-server-windows-aarch64.exe
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.platform.target }}
cache-shared-key: release-windows-${{ matrix.platform.target }}
- name: Build binary
run: cargo build --package nodeget-server --target ${{ matrix.platform.target }} --profile minimal --jobs 32
env:
CROSS_NO_WARNINGS: 0
- name: Rename binary
run: copy target\${{ matrix.platform.target }}\minimal\nodeget-server.exe target\${{ matrix.platform.target }}\minimal\${{ matrix.platform.binary_name }}
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: server-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
if-no-files-found: error
retention-days: 14
build-windows-agent:
name: Build Agent - ${{ matrix.platform.release_for }}
needs: prepare
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
platform:
- release_for: windows_x86_64
target: x86_64-pc-windows-msvc
binary_name: nodeget-agent-windows-x86_64.exe
- release_for: windows_aarch64
target: aarch64-pc-windows-msvc
binary_name: nodeget-agent-windows-aarch64.exe
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.platform.target }}
cache-shared-key: release-agent-windows-${{ matrix.platform.target }}
- name: Build binary
run: cargo build --package nodeget-agent --target ${{ matrix.platform.target }} --profile minimal --jobs 32
env:
CROSS_NO_WARNINGS: 0
- name: Rename binary
run: copy target\${{ matrix.platform.target }}\minimal\nodeget-agent.exe target\${{ matrix.platform.target }}\minimal\${{ matrix.platform.binary_name }}
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: agent-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
if-no-files-found: error
retention-days: 14
build-macos-server:
name: Build Server - ${{ matrix.platform.release_for }}
needs: prepare
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
platform:
- release_for: macos_aarch64
target: aarch64-apple-darwin
binary_name: nodeget-server-macos-aarch64
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.platform.target }}
cache-shared-key: release-macos-${{ matrix.platform.target }}
- name: Build binary
run: cargo build --package nodeget-server --target ${{ matrix.platform.target }} --profile minimal --jobs 32
env:
CROSS_NO_WARNINGS: 0
- name: Rename binary
run: cp target/${{ matrix.platform.target }}/minimal/nodeget-server target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: server-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
if-no-files-found: error
retention-days: 14
build-macos-agent:
name: Build Agent - ${{ matrix.platform.release_for }}
needs: prepare
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
platform:
- release_for: macos_aarch64
target: aarch64-apple-darwin
binary_name: nodeget-agent-macos-aarch64
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Rust
uses: ./.github/actions/setup-rust
with:
targets: ${{ matrix.platform.target }}
cache-shared-key: release-agent-macos-${{ matrix.platform.target }}
- name: Build binary
run: cargo build --package nodeget-agent --target ${{ matrix.platform.target }} --profile minimal --jobs 32
env:
CROSS_NO_WARNINGS: 0
- name: Rename binary
run: cp target/${{ matrix.platform.target }}/minimal/nodeget-agent target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: agent-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/minimal/${{ matrix.platform.binary_name }}
if-no-files-found: error
retention-days: 14
publish-release:
name: Publish GitHub Release
needs:
- prepare
- build-linux-server
- build-windows-server
- build-macos-server
- build-linux-agent
- build-windows-agent
- build-macos-agent
if: needs.prepare.outputs.publish == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true
- name: Upload release assets
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ needs.prepare.outputs.tag }}
name: NodeGet ${{ needs.prepare.outputs.tag }}
make_latest: true
files: dist/*
publish-docker-server:
name: Publish Docker image
needs:
- prepare
- build-linux-server
if: needs.prepare.outputs.publish == 'true'
runs-on: ubuntu-latest
permissions:
actions: write
contents: read
packages: write
env:
REGISTRY: docker.io
IMAGE_NAME: genshinmc/nodeget
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Check Docker Hub credentials
shell: bash
run: |
test -n "${DOCKERHUB_USERNAME}"
test -n "${DOCKERHUB_TOKEN}"
- name: Download Linux musl binaries
uses: actions/download-artifact@v8
with:
pattern: server-*-musl
path: downloads
merge-multiple: true
- name: Prepare bin directory
shell: bash
run: |
mkdir -p bin
cp downloads/nodeget-server-linux-x86_64-musl bin/nodeget-server-amd64
cp downloads/nodeget-server-linux-aarch64-musl bin/nodeget-server-arm64
chmod 0755 bin/nodeget-server-amd64 bin/nodeget-server-arm64
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ env.DOCKERHUB_USERNAME }}
password: ${{ env.DOCKERHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest
type=raw,value=${{ needs.prepare.outputs.tag }}
- name: Build and push
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: runtime
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max