Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 166 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
name: CI & Release

on:
push:
branches: [master]
tags: ['v*']
pull_request:
branches: [master]

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
target: x86_64-unknown-linux-gnu
platform: linux-x86_64
archive_ext: tar.gz

- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
platform: linux-aarch64
archive_ext: tar.gz

- os: macos-14
target: aarch64-apple-darwin
platform: macos-arm64
archive_ext: tar.gz

- os: windows-2025
target: x86_64-pc-windows-msvc
platform: windows-x86_64
archive_ext: zip

runs-on: ${{ matrix.os }}

# Must match OpenMS's MACOSX_DEPLOYMENT_TARGET (see pyOpenMS pyproject.toml
# and openms_ci_matrix_full.yml) to avoid deployment target mismatch warnings
# when linking the static library into OpenMS/pyOpenMS.
env:
MACOSX_DEPLOYMENT_TARGET: ${{ startsWith(matrix.os, 'macos') && '14.0' || '' }}

steps:
# actions/checkout v6.0.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd

- name: Install Rust toolchain
# dtolnay/rust-toolchain stable branch
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7
with:
toolchain: stable

- name: Cache Cargo
# Swatinem/rust-cache v2.8.2
uses: Swatinem/rust-cache@401aff9a7a08acb9d27b64936a90db81024cff97

- name: Run tests
run: cargo test --features with_timsrust

- name: Build release
run: cargo build --features with_timsrust --release

- name: Smoke test (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
g++ -std=c++17 examples/cpp_client.cpp \
-Iinclude \
target/release/libtimsrust_cpp_bridge.a \
-lpthread -ldl -lm \
-o target/smoke_test
# Run with no args — expect exit code 1 (usage), fail only on signal/crash
target/smoke_test || if [ $? -gt 128 ]; then exit 1; fi

- name: Smoke test (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
clang++ -std=c++17 examples/cpp_client.cpp \
-Iinclude \
target/release/libtimsrust_cpp_bridge.a \
-framework Security -framework SystemConfiguration -framework CoreFoundation \
-lresolv -lpthread \
-o target/smoke_test
# Run with no args — expect exit code 1 (usage), fail only on signal/crash
target/smoke_test || if [ $? -gt 128 ]; then exit 1; fi

- name: Setup MSVC dev environment
if: runner.os == 'Windows'
# ilammy/msvc-dev-cmd v1.13.0
uses: ilammy/msvc-dev-cmd@a102174a2b586eec2ea151a69e6fd14404a8ce7c

- name: Smoke test (Windows)
if: runner.os == 'Windows'
shell: cmd
run: |
cl.exe /std:c++17 /EHsc /MD /Fe:target\smoke_test.exe /I include examples\cpp_client.cpp target\release\timsrust_cpp_bridge.lib ws2_32.lib userenv.lib bcrypt.lib ntdll.lib advapi32.lib
target\smoke_test.exe
if %errorlevel% GEQ 2 exit /b %errorlevel%
exit /b 0

- name: Set version
id: version
shell: bash
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "version=${GITHUB_REF#refs/tags/v}" >> "$GITHUB_OUTPUT"
else
echo "version=0.0.0-dev" >> "$GITHUB_OUTPUT"
fi

- name: Package
shell: bash
run: bash scripts/package.sh "${{ steps.version.outputs.version }}" "${{ matrix.target }}"

- name: Validate CMake package
shell: bash
run: |
ARCHIVE_DIR="target/package/timsrust_cpp_bridge-v${{ steps.version.outputs.version }}-${{ matrix.platform }}/timsrust_cpp_bridge"
mkdir -p /tmp/timsrust_cmake_test
cat > /tmp/timsrust_cmake_test/CMakeLists.txt << 'CMAKEOF'
cmake_minimum_required(VERSION 3.11)
project(test_consumer CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(timsrust_cpp_bridge REQUIRED)
add_executable(test_consumer test.cpp)
target_link_libraries(test_consumer timsrust_cpp_bridge::timsrust_cpp_bridge)
CMAKEOF
cat > /tmp/timsrust_cmake_test/test.cpp << 'CPPEOF'
#include "timsrust_cpp_bridge.h"
int main() { return 0; }
CPPEOF
cmake -S /tmp/timsrust_cmake_test -B /tmp/timsrust_cmake_test/build \
-DCMAKE_PREFIX_PATH="$(pwd)/${ARCHIVE_DIR}"
cmake --build /tmp/timsrust_cmake_test/build
rm -rf /tmp/timsrust_cmake_test

- name: Upload artifact
if: startsWith(github.ref, 'refs/tags/v')
# actions/upload-artifact v7.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: timsrust_cpp_bridge-v${{ steps.version.outputs.version }}-${{ matrix.platform }}
path: target/package/timsrust_cpp_bridge-v${{ steps.version.outputs.version }}-${{ matrix.platform }}.${{ matrix.archive_ext }}

release:
if: startsWith(github.ref, 'refs/tags/v')
needs: build
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Download all artifacts
# actions/download-artifact v8.0.1
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
path: artifacts/

- name: Create GitHub Release
# softprops/action-gh-release v2.5.0
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
with:
files: artifacts/**/*
generate_release_notes: true
33 changes: 33 additions & 0 deletions cmake/timsrust_cpp_bridgeConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# timsrust_cpp_bridgeConfig.cmake
# Config-mode package file for timsrust_cpp_bridge
#
# Provides imported target: timsrust_cpp_bridge::timsrust_cpp_bridge
#
# This file lives at <prefix>/lib/cmake/timsrust_cpp_bridge/timsrust_cpp_bridgeConfig.cmake
# The prefix is resolved relative to this file's location.

get_filename_component(_TIMSRUST_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE)

if(NOT TARGET timsrust_cpp_bridge::timsrust_cpp_bridge)
add_library(timsrust_cpp_bridge::timsrust_cpp_bridge STATIC IMPORTED)

set_target_properties(timsrust_cpp_bridge::timsrust_cpp_bridge PROPERTIES
IMPORTED_LOCATION "${_TIMSRUST_PREFIX}/lib/@TIMSRUST_LIB_FILENAME@"
INTERFACE_INCLUDE_DIRECTORIES "${_TIMSRUST_PREFIX}/include"
)

# Platform-specific system link dependencies required by the Rust static library.
# These are validated empirically by CI smoke tests on each platform.
if(UNIX AND NOT APPLE)
set_property(TARGET timsrust_cpp_bridge::timsrust_cpp_bridge APPEND PROPERTY
INTERFACE_LINK_LIBRARIES pthread dl m)
elseif(APPLE)
set_property(TARGET timsrust_cpp_bridge::timsrust_cpp_bridge APPEND PROPERTY
INTERFACE_LINK_LIBRARIES "-framework Security" "-framework SystemConfiguration" "-framework CoreFoundation" resolv)
elseif(WIN32)
set_property(TARGET timsrust_cpp_bridge::timsrust_cpp_bridge APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ws2_32 userenv bcrypt ntdll advapi32)
endif()
endif()

unset(_TIMSRUST_PREFIX)
23 changes: 23 additions & 0 deletions cmake/timsrust_cpp_bridgeConfigVersion.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# timsrust_cpp_bridgeConfigVersion.cmake
# Auto-generated version compatibility file — SameMinorVersion semantics.

set(PACKAGE_VERSION "@TIMSRUST_VERSION_MAJOR@.@TIMSRUST_VERSION_MINOR@.@TIMSRUST_VERSION_PATCH@")

if(DEFINED PACKAGE_FIND_VERSION_RANGE)
# Range semantics are not implemented in this template.
set(PACKAGE_VERSION_COMPATIBLE FALSE)
elseif(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
# SameMinorVersion: major and minor must match exactly
if("@TIMSRUST_VERSION_MAJOR@" EQUAL PACKAGE_FIND_VERSION_MAJOR
AND "@TIMSRUST_VERSION_MINOR@" EQUAL PACKAGE_FIND_VERSION_MINOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()

if(PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
87 changes: 87 additions & 0 deletions scripts/package.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
#
# Package timsrust_cpp_bridge release artifacts.
#
# Usage: scripts/package.sh <version> <target-triple>
# e.g.: scripts/package.sh 0.1.0 x86_64-unknown-linux-gnu
#
# Expects cargo build --release to have been run already.
# Outputs: timsrust_cpp_bridge-v<version>-<platform-label>.tar.gz (or .zip on Windows)

set -euo pipefail

VERSION="${1:?Usage: package.sh <version> <target-triple>}"
TARGET="${2:?Usage: package.sh <version> <target-triple>}"

# Validate version format (semver or 0.0.0-dev for CI)
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
echo "Error: VERSION must be semver (e.g. 1.2.3), got: $VERSION" >&2
exit 1
fi

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# Map Rust target triple to platform label and library filename
case "$TARGET" in
x86_64-unknown-linux-gnu)
PLATFORM="linux-x86_64"
LIB_FILENAME="libtimsrust_cpp_bridge.a"
;;
aarch64-unknown-linux-gnu)
PLATFORM="linux-aarch64"
LIB_FILENAME="libtimsrust_cpp_bridge.a"
;;
aarch64-apple-darwin)
PLATFORM="macos-arm64"
LIB_FILENAME="libtimsrust_cpp_bridge.a"
;;
x86_64-pc-windows-msvc)
PLATFORM="windows-x86_64"
LIB_FILENAME="timsrust_cpp_bridge.lib"
;;
*)
echo "Error: unknown target triple: $TARGET" >&2
exit 1
;;
esac

ARCHIVE_NAME="timsrust_cpp_bridge-v${VERSION}-${PLATFORM}"
STAGING_DIR="$PROJECT_ROOT/target/package/${ARCHIVE_NAME}/timsrust_cpp_bridge"

# Clean and create staging directory
rm -rf "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}"
mkdir -p "$STAGING_DIR/include"
mkdir -p "$STAGING_DIR/lib/cmake/timsrust_cpp_bridge"

# Copy header
cp "$PROJECT_ROOT/include/timsrust_cpp_bridge.h" "$STAGING_DIR/include/"

# Copy static library
cp "$PROJECT_ROOT/target/release/$LIB_FILENAME" "$STAGING_DIR/lib/"

# Configure CMake config file (replace @TIMSRUST_LIB_FILENAME@ placeholder)
sed "s|@TIMSRUST_LIB_FILENAME@|${LIB_FILENAME}|g" \
"$PROJECT_ROOT/cmake/timsrust_cpp_bridgeConfig.cmake.in" \
> "$STAGING_DIR/lib/cmake/timsrust_cpp_bridge/timsrust_cpp_bridgeConfig.cmake"

# Parse version components
IFS='.' read -r V_MAJOR V_MINOR V_PATCH <<< "$VERSION"

# Configure version config file
sed -e "s|@TIMSRUST_VERSION_MAJOR@|${V_MAJOR}|g" \
-e "s|@TIMSRUST_VERSION_MINOR@|${V_MINOR}|g" \
-e "s|@TIMSRUST_VERSION_PATCH@|${V_PATCH}|g" \
"$PROJECT_ROOT/cmake/timsrust_cpp_bridgeConfigVersion.cmake.in" \
> "$STAGING_DIR/lib/cmake/timsrust_cpp_bridge/timsrust_cpp_bridgeConfigVersion.cmake"

# Create archive
cd "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}"
if [[ "$PLATFORM" == windows-* ]]; then
rm -f "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}.zip"
7z a -tzip "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}.zip" timsrust_cpp_bridge/
echo "Created: target/package/${ARCHIVE_NAME}.zip"
else
tar czf "$PROJECT_ROOT/target/package/${ARCHIVE_NAME}.tar.gz" timsrust_cpp_bridge/
echo "Created: target/package/${ARCHIVE_NAME}.tar.gz"
fi
Loading