feat: Add CI/CD workflows for testing and publishing SAL crates
Some checks failed
Test Publishing Setup / Test Publishing Setup (pull_request) Has been cancelled

- Add a workflow for testing the publishing setup
- Add a workflow for publishing SAL crates to crates.io
- Improve crate metadata and version management
- Add optional dependencies for modularity
- Improve documentation for publishing and usage
This commit is contained in:
Mahmoud-Emad
2025-07-01 08:34:20 +03:00
parent 52f2f7e3c4
commit e01b83f12a
29 changed files with 2823 additions and 35 deletions

227
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,227 @@
name: Publish SAL Crates
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version to publish (e.g., 0.1.0)'
required: true
type: string
dry_run:
description: 'Dry run (do not actually publish)'
required: false
type: boolean
default: false
env:
CARGO_TERM_COLOR: always
jobs:
publish:
name: Publish to crates.io
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache Cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install cargo-edit for version management
run: cargo install cargo-edit
- name: Set version from release tag
if: github.event_name == 'release'
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "PUBLISH_VERSION=$VERSION" >> $GITHUB_ENV
echo "Publishing version: $VERSION"
- name: Set version from workflow input
if: github.event_name == 'workflow_dispatch'
run: |
echo "PUBLISH_VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
echo "Publishing version: ${{ github.event.inputs.version }}"
- name: Update version in all crates
run: |
echo "Updating version to $PUBLISH_VERSION"
# Update root Cargo.toml
cargo set-version $PUBLISH_VERSION
# Update each crate
CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai)
for crate in "${CRATES[@]}"; do
if [ -d "$crate" ]; then
cd "$crate"
cargo set-version $PUBLISH_VERSION
cd ..
echo "Updated $crate to version $PUBLISH_VERSION"
fi
done
- name: Run tests
run: cargo test --workspace --verbose
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
- name: Dry run publish (check packages)
run: |
echo "Checking all packages can be published..."
CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai)
for crate in "${CRATES[@]}"; do
if [ -d "$crate" ]; then
echo "Checking $crate..."
cd "$crate"
cargo publish --dry-run
cd ..
fi
done
echo "Checking main crate..."
cargo publish --dry-run
- name: Publish crates (dry run)
if: github.event.inputs.dry_run == 'true'
run: |
echo "🔍 DRY RUN MODE - Would publish the following crates:"
echo "Individual crates: sal-os, sal-process, sal-text, sal-net, sal-git, sal-vault, sal-kubernetes, sal-virt, sal-redisclient, sal-postgresclient, sal-zinit-client, sal-mycelium, sal-rhai"
echo "Meta-crate: sal"
echo "Version: $PUBLISH_VERSION"
- name: Publish individual crates
if: github.event.inputs.dry_run != 'true'
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
echo "Publishing individual crates..."
# Crates in dependency order
CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai)
for crate in "${CRATES[@]}"; do
if [ -d "$crate" ]; then
echo "Publishing sal-$crate..."
cd "$crate"
# Retry logic for transient failures
for attempt in 1 2 3; do
if cargo publish --token $CARGO_REGISTRY_TOKEN; then
echo "✅ sal-$crate published successfully"
break
else
if [ $attempt -eq 3 ]; then
echo "❌ Failed to publish sal-$crate after 3 attempts"
exit 1
else
echo "⚠️ Attempt $attempt failed, retrying in 30 seconds..."
sleep 30
fi
fi
done
cd ..
# Wait for crates.io to process
if [ "$crate" != "rhai" ]; then
echo "⏳ Waiting 30 seconds for crates.io to process..."
sleep 30
fi
fi
done
- name: Publish main crate
if: github.event.inputs.dry_run != 'true'
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
echo "Publishing main sal crate..."
# Wait a bit longer before publishing the meta-crate
echo "⏳ Waiting 60 seconds for all individual crates to be available..."
sleep 60
# Retry logic for the main crate
for attempt in 1 2 3; do
if cargo publish --token $CARGO_REGISTRY_TOKEN; then
echo "✅ Main sal crate published successfully"
break
else
if [ $attempt -eq 3 ]; then
echo "❌ Failed to publish main sal crate after 3 attempts"
exit 1
else
echo "⚠️ Attempt $attempt failed, retrying in 60 seconds..."
sleep 60
fi
fi
done
- name: Create summary
if: always()
run: |
echo "## 📦 SAL Publishing Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** $PUBLISH_VERSION" >> $GITHUB_STEP_SUMMARY
echo "**Trigger:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ github.event.inputs.dry_run }}" == "true" ]; then
echo "**Mode:** Dry Run" >> $GITHUB_STEP_SUMMARY
else
echo "**Mode:** Live Publishing" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Published Crates" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- sal-os" >> $GITHUB_STEP_SUMMARY
echo "- sal-process" >> $GITHUB_STEP_SUMMARY
echo "- sal-text" >> $GITHUB_STEP_SUMMARY
echo "- sal-net" >> $GITHUB_STEP_SUMMARY
echo "- sal-git" >> $GITHUB_STEP_SUMMARY
echo "- sal-vault" >> $GITHUB_STEP_SUMMARY
echo "- sal-kubernetes" >> $GITHUB_STEP_SUMMARY
echo "- sal-virt" >> $GITHUB_STEP_SUMMARY
echo "- sal-redisclient" >> $GITHUB_STEP_SUMMARY
echo "- sal-postgresclient" >> $GITHUB_STEP_SUMMARY
echo "- sal-zinit-client" >> $GITHUB_STEP_SUMMARY
echo "- sal-mycelium" >> $GITHUB_STEP_SUMMARY
echo "- sal-rhai" >> $GITHUB_STEP_SUMMARY
echo "- sal (meta-crate)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Usage" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
echo "# Individual crates" >> $GITHUB_STEP_SUMMARY
echo "cargo add sal-os sal-process sal-text" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "# Meta-crate with features" >> $GITHUB_STEP_SUMMARY
echo "cargo add sal --features core" >> $GITHUB_STEP_SUMMARY
echo "cargo add sal --features all" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

233
.github/workflows/test-publish.yml vendored Normal file
View File

@@ -0,0 +1,233 @@
name: Test Publishing Setup
on:
push:
branches: [ main, master ]
paths:
- '**/Cargo.toml'
- 'scripts/publish-all.sh'
- '.github/workflows/publish.yml'
pull_request:
branches: [ main, master ]
paths:
- '**/Cargo.toml'
- 'scripts/publish-all.sh'
- '.github/workflows/publish.yml'
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
jobs:
test-publish-setup:
name: Test Publishing Setup
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache Cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-publish-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-publish-test-
${{ runner.os }}-cargo-
- name: Install cargo-edit
run: cargo install cargo-edit
- name: Test workspace structure
run: |
echo "Testing workspace structure..."
# Check that all expected crates exist
EXPECTED_CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai herodo)
for crate in "${EXPECTED_CRATES[@]}"; do
if [ -d "$crate" ] && [ -f "$crate/Cargo.toml" ]; then
echo "✅ $crate exists"
else
echo "❌ $crate missing or invalid"
exit 1
fi
done
- name: Test feature configuration
run: |
echo "Testing feature configuration..."
# Test that features work correctly
cargo check --features os
cargo check --features process
cargo check --features text
cargo check --features net
cargo check --features git
cargo check --features vault
cargo check --features kubernetes
cargo check --features virt
cargo check --features redisclient
cargo check --features postgresclient
cargo check --features zinit_client
cargo check --features mycelium
cargo check --features rhai
echo "✅ All individual features work"
# Test feature groups
cargo check --features core
cargo check --features clients
cargo check --features infrastructure
cargo check --features scripting
echo "✅ All feature groups work"
# Test all features
cargo check --features all
echo "✅ All features together work"
- name: Test dry-run publishing
run: |
echo "Testing dry-run publishing..."
# Test each individual crate can be packaged
CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai)
for crate in "${CRATES[@]}"; do
echo "Testing sal-$crate..."
cd "$crate"
cargo publish --dry-run
cd ..
echo "✅ sal-$crate can be published"
done
# Test main crate
echo "Testing main sal crate..."
cargo publish --dry-run
echo "✅ Main sal crate can be published"
- name: Test publishing script
run: |
echo "Testing publishing script..."
# Make script executable
chmod +x scripts/publish-all.sh
# Test dry run
./scripts/publish-all.sh --dry-run --version 0.1.0-test
echo "✅ Publishing script works"
- name: Test version consistency
run: |
echo "Testing version consistency..."
# Get version from root Cargo.toml
ROOT_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
echo "Root version: $ROOT_VERSION"
# Check all crates have the same version
CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai herodo)
for crate in "${CRATES[@]}"; do
if [ -f "$crate/Cargo.toml" ]; then
CRATE_VERSION=$(grep '^version = ' "$crate/Cargo.toml" | head -1 | sed 's/version = "\(.*\)"/\1/')
if [ "$CRATE_VERSION" = "$ROOT_VERSION" ]; then
echo "✅ $crate version matches: $CRATE_VERSION"
else
echo "❌ $crate version mismatch: $CRATE_VERSION (expected $ROOT_VERSION)"
exit 1
fi
fi
done
- name: Test metadata completeness
run: |
echo "Testing metadata completeness..."
# Check that all crates have required metadata
CRATES=(os process text net git vault kubernetes virt redisclient postgresclient zinit_client mycelium rhai)
for crate in "${CRATES[@]}"; do
echo "Checking sal-$crate metadata..."
cd "$crate"
# Check required fields exist
if ! grep -q '^name = "sal-' Cargo.toml; then
echo "❌ $crate missing or incorrect name"
exit 1
fi
if ! grep -q '^description = ' Cargo.toml; then
echo "❌ $crate missing description"
exit 1
fi
if ! grep -q '^repository = ' Cargo.toml; then
echo "❌ $crate missing repository"
exit 1
fi
if ! grep -q '^license = ' Cargo.toml; then
echo "❌ $crate missing license"
exit 1
fi
echo "✅ sal-$crate metadata complete"
cd ..
done
- name: Test dependency resolution
run: |
echo "Testing dependency resolution..."
# Test that all workspace dependencies resolve correctly
cargo tree --workspace > /dev/null
echo "✅ All dependencies resolve correctly"
# Test that there are no dependency conflicts
cargo check --workspace
echo "✅ No dependency conflicts"
- name: Generate publishing report
if: always()
run: |
echo "## 🧪 Publishing Setup Test Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ✅ Tests Passed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Workspace structure validation" >> $GITHUB_STEP_SUMMARY
echo "- Feature configuration testing" >> $GITHUB_STEP_SUMMARY
echo "- Dry-run publishing simulation" >> $GITHUB_STEP_SUMMARY
echo "- Publishing script validation" >> $GITHUB_STEP_SUMMARY
echo "- Version consistency check" >> $GITHUB_STEP_SUMMARY
echo "- Metadata completeness verification" >> $GITHUB_STEP_SUMMARY
echo "- Dependency resolution testing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 📦 Ready for Publishing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "All SAL crates are ready for publishing to crates.io!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Individual Crates:** 13 modules" >> $GITHUB_STEP_SUMMARY
echo "**Meta-crate:** sal with optional features" >> $GITHUB_STEP_SUMMARY
echo "**Binary:** herodo script executor" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### 🚀 Next Steps" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "1. Create a release tag (e.g., v0.1.0)" >> $GITHUB_STEP_SUMMARY
echo "2. The publish workflow will automatically trigger" >> $GITHUB_STEP_SUMMARY
echo "3. All crates will be published to crates.io" >> $GITHUB_STEP_SUMMARY
echo "4. Users can install with: \`cargo add sal-os\` or \`cargo add sal --features all\`" >> $GITHUB_STEP_SUMMARY