diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e7c18bd --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,304 @@ + +name: Release + +on: + push: + tags: + - 'v*.*.*' # Triggers on tags like v0.1.0, v1.2.3, etc. + workflow_dispatch: # Allows manual triggering + inputs: + version: + description: 'Version to release (e.g., 0.1.0)' + required: true + type: string + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + # First job: Build and verify all crates + verify: + name: Verify Release Build + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v4 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo build + uses: actions/cache@v4 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} + + - name: Run tests + run: cargo test --verbose --all-features + + - name: Build release + run: cargo build --release --all-features + + - name: Verify package builds + run: | + cargo package --package aleph-types --allow-dirty + cargo package --package aleph-sdk --allow-dirty + cargo package --package aleph-cli --allow-dirty + + # Second job: Check version consistency + check-versions: + name: Check Version Consistency + runs-on: ubuntu-latest + outputs: + version: ${{ steps.get-version.outputs.version }} + types-version: ${{ steps.get-version.outputs.types-version }} + sdk-version: ${{ steps.get-version.outputs.sdk-version }} + cli-version: ${{ steps.get-version.outputs.cli-version }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Extract version from tag or input + id: get-version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + VERSION=${GITHUB_REF#refs/tags/v} + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Extract versions from Cargo.toml files + TYPES_VERSION=$(grep '^version = ' crates/aleph-types/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') + SDK_VERSION=$(grep '^version = ' crates/aleph-sdk/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') + CLI_VERSION=$(grep '^version = ' crates/aleph-cli/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') + + echo "types-version=$TYPES_VERSION" >> $GITHUB_OUTPUT + echo "sdk-version=$SDK_VERSION" >> $GITHUB_OUTPUT + echo "cli-version=$CLI_VERSION" >> $GITHUB_OUTPUT + + echo "Tag version: $VERSION" + echo "aleph-types version: $TYPES_VERSION" + echo "aleph-sdk version: $SDK_VERSION" + echo "aleph-cli version: $CLI_VERSION" + + - name: Verify version consistency + run: | + VERSION="${{ steps.get-version.outputs.version }}" + TYPES_VERSION="${{ steps.get-version.outputs.types-version }}" + SDK_VERSION="${{ steps.get-version.outputs.sdk-version }}" + CLI_VERSION="${{ steps.get-version.outputs.cli-version }}" + + if [ "$VERSION" != "$TYPES_VERSION" ] || [ "$VERSION" != "$SDK_VERSION" ] || [ "$VERSION" != "$CLI_VERSION" ]; then + echo "Error: Version mismatch detected!" + echo "Tag version: $VERSION" + echo "aleph-types: $TYPES_VERSION" + echo "aleph-sdk: $SDK_VERSION" + echo "aleph-cli: $CLI_VERSION" + exit 1 + fi + + echo "✓ All versions are consistent: $VERSION" + + # Third job: Create GitHub release (automatic) + create-release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: [verify, check-versions] + permissions: + contents: write + outputs: + upload_url: ${{ steps.create-release.outputs.upload_url }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Extract changelog + id: changelog + run: | + VERSION="${{ needs.check-versions.outputs.version }}" + # Extract changelog section for this version (if you maintain a CHANGELOG.md) + if [ -f CHANGELOG.md ]; then + CHANGELOG=$(sed -n "/## \[$VERSION\]/,/## \[/p" CHANGELOG.md | sed '$ d') + else + CHANGELOG="Release version $VERSION" + fi + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create Release + id: create-release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ needs.check-versions.outputs.version }} + release_name: Release v${{ needs.check-versions.outputs.version }} + body: | + ## aleph-rs v${{ needs.check-versions.outputs.version }} + + ### Crates Released + - `aleph-types` v${{ needs.check-versions.outputs.version }} + - `aleph-sdk` v${{ needs.check-versions.outputs.version }} + - `aleph-cli` v${{ needs.check-versions.outputs.version }} + + ### Changes + ${{ steps.changelog.outputs.changelog }} + + ### Installation + ```toml + [dependencies] + aleph-types = "${{ needs.check-versions.outputs.version }}" + aleph-sdk = "${{ needs.check-versions.outputs.version }}" + ``` + + Or with cargo: + ```bash + cargo install aleph-cli --version ${{ needs.check-versions.outputs.version }} + ``` + draft: false + prerelease: ${{ contains(needs.check-versions.outputs.version, '-') }} + + # Fourth job: Build release binaries + build-binaries: + name: Build Release Binaries + needs: [check-versions, create-release] + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + artifact_name: aleph-cli + asset_name: aleph-cli-linux-x86_64 + - os: windows-latest + target: x86_64-pc-windows-msvc + artifact_name: aleph-cli.exe + asset_name: aleph-cli-windows-x86_64.exe + - os: macos-latest + target: x86_64-apple-darwin + artifact_name: aleph-cli + asset_name: aleph-cli-macos-x86_64 + - os: macos-latest + target: aarch64-apple-darwin + artifact_name: aleph-cli + asset_name: aleph-cli-macos-aarch64 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Build release binary + run: cargo build --release --package aleph-cli --target ${{ matrix.target }} + + - name: Upload Release Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: ./target/${{ matrix.target }}/release/${{ matrix.artifact_name }} + asset_name: ${{ matrix.asset_name }} + asset_content_type: application/octet-stream + + # Fifth job: Manual approval step before publishing to crates.io + request-publish-approval: + name: Request Publish Approval + runs-on: ubuntu-latest + needs: [verify, check-versions, create-release] + environment: + name: crates-io-publish # Requires manual approval in GitHub + steps: + - name: Approval checkpoint + run: | + echo "✓ All checks passed" + echo "✓ GitHub release created" + echo "✓ Ready to publish to crates.io" + echo "" + echo "Crates to be published:" + echo " - aleph-types v${{ needs.check-versions.outputs.version }}" + echo " - aleph-sdk v${{ needs.check-versions.outputs.version }}" + echo " - aleph-cli v${{ needs.check-versions.outputs.version }}" + + # Sixth job: Publish to crates.io (only runs after manual approval) + publish-crates: + name: Publish to crates.io + runs-on: ubuntu-latest + needs: [check-versions, request-publish-approval] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Publish aleph-types + run: | + cd crates/aleph-types + cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + continue-on-error: false + + - name: Wait for aleph-types to be available + run: | + echo "Waiting 30 seconds for aleph-types to propagate on crates.io..." + sleep 30 + + - name: Publish aleph-sdk + run: | + cd crates/aleph-sdk + cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + continue-on-error: false + + - name: Wait for aleph-sdk to be available + run: | + echo "Waiting 30 seconds for aleph-sdk to propagate on crates.io..." + sleep 30 + + - name: Publish aleph-cli + run: | + cd crates/aleph-cli + cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} + continue-on-error: false + + - name: Update release with crates.io links + uses: actions/github-script@v7 + with: + script: | + const version = '${{ needs.check-versions.outputs.version }}'; + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + }); + const release = releases.data.find(r => r.tag_name === `v${version}`); + if (release) { + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.id, + body: release.body + '\n\n---\n✅ **Published to crates.io**\n' + + `- [aleph-types](https://crates.io/crates/aleph-types/${version})\n` + + `- [aleph-sdk](https://crates.io/crates/aleph-sdk/${version})\n` + + `- [aleph-cli](https://crates.io/crates/aleph-cli/${version})\n` + }); + } \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef58e21 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# aleph-rs + +[![CI](https://github.com/aleph-im/aleph-rs/workflows/CI/badge.svg)](https://github.com/aleph-im/aleph-rs/actions) + +Rust tools for the Aleph Cloud protocol. +This repository is meant to be a mono-repo for everything related to Aleph Cloud written in Rust. + +## Overview + +This repository provides three crates at the moment: + +- **[aleph-types](crates/aleph-types)** - Core type definitions +- **[aleph-sdk](crates/aleph-sdk)** - Rust SDK for interacting with Aleph Cloud nodes +- **[aleph-cli](crates/aleph-cli)** - Command-line interface built on top of the SDK. + +## Features + +- 🦀 **Type-safe** - Strongly typed Rust implementation of the Aleph Cloud protocol +- 🔄 **Async/Await** - Built on Tokio for efficient async operations +- 🧪 **Well-tested** - Comprehensive test suite with CI/CD +- 🌐 **Cross-platform** - Tested on Linux, macOS, and Windows +- 📦 **Modular** - Separate crates for types, SDK, and CLI + +## Quick Start + +### Using the SDK + +Add the following to your `Cargo.toml`: + +```toml +[dependencies] +aleph-sdk = { git = "[https://github.com/aleph-im/aleph-rs](https://github.com/aleph-im/aleph-rs)" } +aleph-types = { git = "[https://github.com/aleph-im/aleph-rs](https://github.com/aleph-im/aleph-rs)" } +``` + +Basic usage example: + +```rust +use aleph_sdk::AlephClient; +use aleph_types::message::Post; +use aleph_types::item_hash; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let client = AlephClient::new("https://api2.aleph.im")?; + + // In this example, we fetch a message from the network. + let item_hash = item_hash!("f3862cf9d3ad73a9e82b1c56fed12627ec51c6d2a1e3189ab3ef289642711b3e"); + let message = client.get_message(item_hash).await?; + + Ok(()) +} +``` \ No newline at end of file diff --git a/crates/aleph-sdk/README.md b/crates/aleph-sdk/README.md new file mode 100644 index 0000000..48e63fa --- /dev/null +++ b/crates/aleph-sdk/README.md @@ -0,0 +1,63 @@ +# aleph-sdk + +A Rust SDK to interact with Aleph Cloud. + +## Overview + +The Aleph Cloud SDK provides a Rust async API to interact with Aleph Cloud. +This SDK is currently in development and only supports a minimal set of features: + +* Message listing and filtering +* Querying individual messages by item hash. + +## Installation + +Add the following to your `Cargo.toml`: + +```toml +[dependencies] +aleph-sdk = { git = "https://github.com/aleph-im/aleph-rs" } +aleph-types = { git = "https://github.com/aleph-im/aleph-rs" } +``` + +## Examples + +### Fetch a single message by item hash + +```rust +use aleph_sdk::AlephClient; +use aleph_types::message::Post; +use aleph_types::item_hash; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let client = AlephClient::new("https://api2.aleph.im")?; + + // In this example, we fetch a message from the network. + let item_hash = item_hash!("f3862cf9d3ad73a9e82b1c56fed12627ec51c6d2a1e3189ab3ef289642711b3e"); + let message = client.get_message(item_hash).await?; + + Ok(()) +} +``` + +### Filter messages by sender + +```rust +#[tokio::main] +use aleph_sdk::client::{AlephClient, MessageFilter}; +use aleph_types::item_hash; + +async fn main() -> anyhow::Result<()> { + let client = AlephClient::new("https://api2.aleph.im")?; + + let address = address!("0x1234567890123456789012345678901234567890");; + let message_filter = MessageFilter {address: Some(address), ..Default::default()}; + + // Fetch all messages sent by the given address. + let messages = client.get_messages(message_filter).await?; + + Ok(()) +} +``` +``` \ No newline at end of file diff --git a/crates/aleph-types/README.md b/crates/aleph-types/README.md new file mode 100644 index 0000000..bf185bc --- /dev/null +++ b/crates/aleph-types/README.md @@ -0,0 +1,22 @@ +# aleph-types + +Core type definitions for the Aleph Cloud protocol. + +## Overview +This crate provides strongly-typed Rust implementations of all Aleph.im protocol types, including messages, channels, +storage specifications, and cryptographic primitives. + +## Features + +* 📦 Message Types - Complete type definitions for all Aleph message types: + * Post - Content posts + * Aggregate - Key-value aggregates + * Store - File storage references + * Program - VM program specifications + * Instance - Persistent VM instances + * Forget - Content deletion requests +* 🔐 Item Hashing - SHA-256 based content addressing with `ItemHash` +* 🌐 Chain Support - Blockchain identifiers and specifications +* 📡 Channel Management - Message channel definitions +* ⏰ Timestamps - Unix timestamp handling +* 📏 Storage Sizes - Human-readable storage size types \ No newline at end of file