name: Release on: push: tags: - '[0-9]+.[0-9]+.[0-9]+' workflow_dispatch: inputs: tag: description: 'Release tag (example: 3.3.15)' required: true type: string concurrency: group: release-${{ github.ref_name }}-${{ github.event.inputs.tag || 'auto' }} cancel-in-progress: true permissions: contents: read env: CARGO_TERM_COLOR: always BINARY_NAME: telemt jobs: prepare: name: Prepare runs-on: ubuntu-latest outputs: version: ${{ steps.vars.outputs.version }} prerelease: ${{ steps.vars.outputs.prerelease }} steps: - name: Resolve version id: vars shell: bash run: | set -euo pipefail if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then VERSION="${{ github.event.inputs.tag }}" else VERSION="${GITHUB_REF#refs/tags/}" fi VERSION="${VERSION#refs/tags/}" if [ -z "${VERSION}" ]; then echo "Release version is empty" >&2 exit 1 fi if [[ "${VERSION}" == *-* ]]; then PRERELEASE=true else PRERELEASE=false fi echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" echo "prerelease=${PRERELEASE}" >> "${GITHUB_OUTPUT}" # ========================== # GNU / glibc # ========================== build-gnu: name: GNU ${{ matrix.asset }} runs-on: ubuntu-latest needs: prepare container: image: rust:slim-bookworm strategy: fail-fast: false matrix: include: - target: x86_64-unknown-linux-gnu asset: telemt-x86_64-linux-gnu cpu: baseline - target: x86_64-unknown-linux-gnu asset: telemt-x86_64-v3-linux-gnu cpu: v3 - target: aarch64-unknown-linux-gnu asset: telemt-aarch64-linux-gnu cpu: generic steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@v1 with: toolchain: stable targets: | x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu - name: Install deps run: | apt-get update apt-get install -y \ build-essential \ clang \ lld \ pkg-config \ gcc-aarch64-linux-gnu \ g++-aarch64-linux-gnu - uses: actions/cache@v4 with: path: | /usr/local/cargo/registry /usr/local/cargo/git target key: gnu-${{ matrix.asset }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | gnu-${{ matrix.asset }}- gnu- - name: Build shell: bash run: | set -euo pipefail if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then export CC=aarch64-linux-gnu-gcc export CXX=aarch64-linux-gnu-g++ export RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C lto=fat -C panic=abort" else export CC=clang export CXX=clang++ if [ "${{ matrix.cpu }}" = "v3" ]; then CPU_FLAGS="-C target-cpu=x86-64-v3" else CPU_FLAGS="-C target-cpu=x86-64" fi export RUSTFLAGS="-C linker=clang -C link-arg=-fuse-ld=lld -C lto=fat -C panic=abort ${CPU_FLAGS}" fi cargo build --release --target ${{ matrix.target }} -j "$(nproc)" - name: Package shell: bash run: | set -euo pipefail mkdir -p dist cp "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}" dist/telemt if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then STRIP_BIN=aarch64-linux-gnu-strip else STRIP_BIN=strip fi "${STRIP_BIN}" dist/telemt cd dist tar -czf "${{ matrix.asset }}.tar.gz" \ --owner=0 --group=0 --numeric-owner \ telemt sha256sum "${{ matrix.asset }}.tar.gz" > "${{ matrix.asset }}.tar.gz.sha256" - uses: actions/upload-artifact@v4 with: name: ${{ matrix.asset }} path: dist/* # ========================== # MUSL # ========================== build-musl: name: MUSL ${{ matrix.asset }} runs-on: ubuntu-latest needs: prepare container: image: rust:slim-bookworm strategy: fail-fast: false matrix: include: - target: x86_64-unknown-linux-musl asset: telemt-x86_64-linux-musl cpu: baseline - target: x86_64-unknown-linux-musl asset: telemt-x86_64-v3-linux-musl cpu: v3 - target: aarch64-unknown-linux-musl asset: telemt-aarch64-linux-musl cpu: generic steps: - uses: actions/checkout@v4 - name: Install deps run: | apt-get update apt-get install -y \ musl-tools \ pkg-config \ curl - uses: actions/cache@v4 if: matrix.target == 'aarch64-unknown-linux-musl' with: path: ~/.musl-aarch64 key: musl-toolchain-aarch64-v1 - name: Install aarch64 musl toolchain if: matrix.target == 'aarch64-unknown-linux-musl' shell: bash run: | set -euo pipefail TOOLCHAIN_DIR="$HOME/.musl-aarch64" ARCHIVE="aarch64-linux-musl-cross.tgz" URL="https://github.com/telemt/telemt/releases/download/toolchains/${ARCHIVE}" if [ -x "${TOOLCHAIN_DIR}/bin/aarch64-linux-musl-gcc" ]; then echo "MUSL toolchain cached" else curl -fL \ --retry 5 \ --retry-delay 3 \ --connect-timeout 10 \ --max-time 120 \ -o "${ARCHIVE}" "${URL}" mkdir -p "${TOOLCHAIN_DIR}" tar -xzf "${ARCHIVE}" --strip-components=1 -C "${TOOLCHAIN_DIR}" fi echo "${TOOLCHAIN_DIR}/bin" >> "${GITHUB_PATH}" - name: Add rust target run: rustup target add ${{ matrix.target }} - uses: actions/cache@v4 with: path: | /usr/local/cargo/registry /usr/local/cargo/git target key: musl-${{ matrix.asset }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | musl-${{ matrix.asset }}- musl- - name: Build shell: bash run: | set -euo pipefail if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then export CC=aarch64-linux-musl-gcc export CC_aarch64_unknown_linux_musl=aarch64-linux-musl-gcc export RUSTFLAGS="-C target-feature=+crt-static -C linker=aarch64-linux-musl-gcc -C lto=fat -C panic=abort" else export CC=musl-gcc export CC_x86_64_unknown_linux_musl=musl-gcc if [ "${{ matrix.cpu }}" = "v3" ]; then CPU_FLAGS="-C target-cpu=x86-64-v3" else CPU_FLAGS="-C target-cpu=x86-64" fi export RUSTFLAGS="-C target-feature=+crt-static -C lto=fat -C panic=abort ${CPU_FLAGS}" fi cargo build --release --target ${{ matrix.target }} -j "$(nproc)" - name: Package shell: bash run: | set -euo pipefail mkdir -p dist cp "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}" dist/telemt if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then STRIP_BIN=aarch64-linux-musl-strip else STRIP_BIN=strip fi "${STRIP_BIN}" dist/telemt cd dist tar -czf "${{ matrix.asset }}.tar.gz" \ --owner=0 --group=0 --numeric-owner \ telemt sha256sum "${{ matrix.asset }}.tar.gz" > "${{ matrix.asset }}.tar.gz.sha256" - uses: actions/upload-artifact@v4 with: name: ${{ matrix.asset }} path: dist/* # ========================== # Release # ========================== release: name: Release runs-on: ubuntu-latest needs: [prepare, build-gnu, build-musl] permissions: contents: write steps: - uses: actions/download-artifact@v4 with: path: artifacts - name: Flatten artifacts shell: bash run: | set -euo pipefail mkdir -p dist find artifacts -type f -exec cp {} dist/ \; - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ needs.prepare.outputs.version }} target_commitish: ${{ github.sha }} files: dist/* generate_release_notes: true prerelease: ${{ needs.prepare.outputs.prerelease == 'true' }} overwrite_files: true # ========================== # Docker # ========================== docker: name: Docker runs-on: ubuntu-latest needs: [prepare, release] permissions: contents: read packages: write steps: - uses: actions/checkout@v4 - uses: docker/setup-qemu-action@v3 - uses: docker/setup-buildx-action@v3 - uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Probe release assets shell: bash env: VERSION: ${{ needs.prepare.outputs.version }} run: | set -euo pipefail for asset in \ telemt-x86_64-linux-musl.tar.gz \ telemt-x86_64-linux-musl.tar.gz.sha256 \ telemt-aarch64-linux-musl.tar.gz \ telemt-aarch64-linux-musl.tar.gz.sha256 do curl -fsIL \ --retry 10 \ --retry-delay 3 \ "https://github.com/${GITHUB_REPOSITORY}/releases/download/${VERSION}/${asset}" \ > /dev/null done - name: Compute image tags id: meta shell: bash env: VERSION: ${{ needs.prepare.outputs.version }} run: | set -euo pipefail IMAGE="$(echo "ghcr.io/${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')" TAGS="${IMAGE}:${VERSION}" if [[ "${VERSION}" != *-* ]]; then TAGS="${TAGS}"$'\n'"${IMAGE}:latest" fi { echo "tags<> "${GITHUB_OUTPUT}" - name: Build & Push uses: docker/build-push-action@v6 with: context: . push: true pull: true platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} build-args: | TELEMT_REPOSITORY=${{ github.repository }} TELEMT_VERSION=${{ needs.prepare.outputs.version }} cache-from: type=gha cache-to: type=gha,mode=max