diff --git a/.github/WORKFLOW_SETUP.md b/.github/WORKFLOW_SETUP.md new file mode 100644 index 0000000..be70e72 --- /dev/null +++ b/.github/WORKFLOW_SETUP.md @@ -0,0 +1,228 @@ +# GitHub Workflows Setup Guide + +This repository uses **ultra-simple workflows** powered by **Docker + Makefile** architecture. + +## ๐Ÿ—๏ธ **Architecture: Docker + Makefile = Simple + Powerful** + +**Core insight**: Keep GitHub workflows **trivially simple** by moving all complexity into Makefile Docker targets. + +```yaml +# GitHub workflows are dead simple: +steps: + - uses: actions/checkout@v4 + - run: make ci-docker-full +``` + +```makefile +# Makefile handles Docker complexity: +ci-docker-full: + docker run --rm -v $(PWD):/workspaces/project -w /workspaces/project \ + solanafoundation/anchor:v0.31.1 make ci-full +``` + +**Benefits:** + +- โœ… **Dead-simple workflows** - Minimal YAML, maximum power +- โœ… **Local = CI** - Same Docker environment everywhere +- โœ… **Battle-tested tools** - Official Solana Foundation container +- โœ… **Zero drift** - One source of truth in Makefile +- โœ… **Easy debugging** - `make ci-docker-full` reproduces CI exactly + +## ๐Ÿ”ง **The Two Workflows** + +### 1. **CI Workflow** (`.github/workflows/ci.yml`) + +**Triggers:** Push to `main`, all pull requests +**Jobs:** + +- **Quick Checks (Native)** โ†’ `make ci-quick` - Fast feedback on publishable crate +- **Docker Validation (Complete)** โ†’ `make ci-docker-full` - Full workspace in production environment + +### 2. **Release Workflow** (`.github/workflows/release.yml`) + +**Triggers:** Version tags (`v0.1.0`, `v1.2.3`, etc.) +**Jobs:** + +1. **Release Validation** โ†’ `make release-validation` - Complete validation in Docker +2. **Publish** โ†’ `make publish` - Push to crates.io +3. **GitHub Release** - Extract changelog and create release + +## ๐ŸŽฏ **Docker Container: solanafoundation/anchor:v0.31.1** + +This is the **official Anchor Docker image** used by `anchor build --verifiable`: + +- โœ… **Solana CLI** (2.1.0) +- โœ… **Anchor** (0.31.1) +- โœ… **Rust/Cargo** (latest) +- โœ… **cargo-build-sbf** (Solana BPF builder) +- โœ… **Platform tools** (v1.43) + +**No manual installation required** - everything just works! + +## ๐Ÿš€ **Makefile Targets** + +```bash +# Development (native) +make check # Fast workspace check +make test # All tests +make fmt # Format code +make ci-local # Local CI with full tools + +# Docker CI (matches production) +make ci-docker-quick # Fast CI in Docker +make ci-docker-full # Complete CI in Docker +make ci # Main CI target (Docker-based) + +# Release +make release-validation # Complete release checks +make publish # Publish to crates.io +``` + +## โš™๏ธ **Setup Requirements** + +### **Required GitHub Secrets** + +**Settings โ†’ Secrets and variables โ†’ Actions:** + +1. **`CARGO_REGISTRY_TOKEN`** (Required for releases) + + ```bash + # Get from: https://crates.io/me + # Permissions: "Publish new crates" + "Publish updates" + ``` + +2. **`GITHUB_TOKEN`** - Automatically provided, no setup needed + +### **Branch Protection** + +**Settings โ†’ Branches โ†’ Add rule** for `main`: + +- โœ… Require status checks: `Quick Checks (Native)`, `Docker Validation (Complete)` +- โœ… Require up-to-date branches before merging +- โœ… Include administrators + +## ๐Ÿš€ **Publishing Process** + +### **Automatic (Recommended)** + +```bash +# 1. Update version +vim crates/litesvm-testing/Cargo.toml + +# 2. Update changelog +vim CHANGELOG.md + +# 3. Commit and tag +git add -A && git commit -m "Release v0.1.0" +git tag v0.1.0 && git push origin main v0.1.0 + +# 4. Watch automation โœจ +# โ†’ Docker validation +# โ†’ crates.io publishing +# โ†’ GitHub release creation +``` + +### **Local Testing (Before Release)** + +```bash +# Test exact release process locally +TAG_VERSION="0.1.0" make release-validation + +# Or full Docker CI +make ci-docker-full +``` + +## ๐Ÿ› **Debugging CI Issues** + +**The magic of Docker-based CI:** + +```bash +# Reproduce CI failure exactly: +make ci-docker-full + +# Or just the quick checks: +make ci-docker-quick + +# Debug step by step: +docker run --rm -v $(pwd):/workspaces/project -w /workspaces/project \ + solanafoundation/anchor:v0.31.1 bash +# Then run individual commands inside container +``` + +**If `make ci-docker-full` passes locally, CI will pass!** + +## ๐Ÿ“Š **Local Development Workflow** + +```bash +# Fast development loop (native tools) +make check # Quick validation +make test # Run tests +make fmt # Format code + +# Before pushing (Docker validation) +make ci-docker-full # Exact CI environment + +# Quick Docker check +make ci-docker-quick # Fast Docker validation +``` + +## ๐ŸŽฏ **Key Design Principles** + +1. **Workflows are thin wrappers** - Real logic in Makefile +2. **Docker for consistency** - Same environment everywhere +3. **Official containers** - Battle-tested, maintained by Solana Foundation +4. **Parallel jobs** - Fast feedback + thorough validation +5. **Version validation** - Tag must match `Cargo.toml` + +## ๐Ÿ” **Quality Standards** + +Enforced automatically: + +- โœ… **Zero clippy warnings** (`-D warnings`) +- โœ… **Proper formatting** (`cargo fmt --check`) +- โœ… **All tests pass** (including Solana programs) +- โœ… **Documentation builds** cleanly +- โœ… **Publish dry-run** succeeds +- โœ… **Version consistency** (tag โ†” Cargo.toml) + +## ๐Ÿ› ๏ธ **Troubleshooting** + +### **Common Issues** + +**"Tag version doesn't match Cargo.toml"** + +```bash +# Check versions match: +git describe --tags # v0.1.0 +grep '^version = ' crates/litesvm-testing/Cargo.toml # version = "0.1.0" +``` + +**"Docker container fails"** + +```bash +# Test Docker setup locally: +docker pull solanafoundation/anchor:v0.31.1 +make ci-docker-quick +``` + +**"crates.io token invalid"** + +```bash +# Verify secret is set in GitHub: +# Settings โ†’ Secrets โ†’ CARGO_REGISTRY_TOKEN +``` + +### **Advanced Debugging** + +```bash +# Interactive Docker debugging: +docker run -it --rm -v $(pwd):/workspaces/project -w /workspaces/project \ + solanafoundation/anchor:v0.31.1 bash + +# Inside container: +make ci-full # Run full CI +solana --version # Check tool versions +cargo clippy # Test individual commands +``` + +This architecture ensures **reliable, maintainable, and debuggable** CI/CD! ๐ŸŽ‰ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a3a92e7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,56 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +jobs: + # Quick CI for the publishable crate (native) + quick-checks: + name: Quick Checks (Native) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + - run: make ci-quick + + # Complete validation in Docker (matches production environment) + docker-validation: + name: Docker Validation (Complete) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Cache Docker layers for faster subsequent builds + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-docker-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-docker- + + # Cache Cargo registry (mounted into container) + - name: Cache Cargo registry + uses: actions/cache@v4 + with: + path: ~/.cargo + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - run: make ci-docker-full diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..692c22d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Release + +on: + push: + tags: + - "v*.*.*" # Triggers on version tags like v0.1.0, v1.2.3, etc. + +env: + CARGO_TERM_COLOR: always + +jobs: + # Validate release in Docker environment + validate: + name: Release Validation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: TAG_VERSION="${GITHUB_REF#refs/tags/v}" make release-validation + + # Publish to crates.io + publish: + name: Publish to crates.io + runs-on: ubuntu-latest + needs: validate + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: make publish + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + + # Create GitHub release with changelog + github-release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: publish + steps: + - uses: actions/checkout@v4 + - name: Extract changelog for this version + run: | + TAG_VERSION="${GITHUB_REF#refs/tags/v}" + sed -n "/## \[$TAG_VERSION\]/,/## \[/p" CHANGELOG.md | sed '$d' > release_notes.md + echo "Release notes for v$TAG_VERSION:" + cat release_notes.md + - uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body_path: release_notes.md + draft: false + prerelease: false diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9607886 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,42 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Steel framework support (planned) +- Enhanced testing utilities (compute units, account state validation) +- Integration with popular Solana testing patterns + +## [0.1.0] - TBD + +### Added + +- Complete error testing framework for transaction, instruction, and system errors +- Type-safe system error assertions using `SystemError` enums +- Log assertion utilities with detailed error messages +- Dual API styles: direct function calls and fluent method chaining +- Precision control: "anywhere" matching vs surgical instruction-index targeting +- Anchor framework integration with automatic compilation and IDL support +- Pinocchio framework integration with lightweight build utilities +- Educational examples showing API progression from verbose to elegant +- Comprehensive documentation with working examples +- Setup utilities for quick SVM and fee payer initialization + +### Documentation + +- Complete API documentation with examples +- Framework-specific integration guides +- Educational test suite demonstrating best practices +- Progressive examples showing Good โ†’ Better โ†’ Best โ†’ Best+ patterns + +### Examples + +- Working Anchor program integration +- Working Pinocchio program integration +- Educational test cases for common error scenarios diff --git a/Cargo.toml b/Cargo.toml index 44bcb3d..8804bc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,13 @@ simple-anchor-tests = { path = "examples/anchor/simple-anchor-tests" } simple-pinocchio-program = { path = "examples/pinocchio/simple-pinocchio-program" } simple-pinocchio-tests = { path = "examples/pinocchio/simple-pinocchio-tests" } -litesvm-testing = { path = "crates/litesvm-testing" } -litesvm = "0.6.1" - anchor-lang = "0.31.1" +litesvm = "0.6.1" +litesvm-testing = { path = "crates/litesvm-testing" } +num-traits = "0.2.19" +pinocchio = "0.8.4" +pinocchio-log = "0.4.0" +pinocchio-pubkey = "0.2.4" solana-compute-budget-interface = "2.2" solana-instruction = "2.2" solana-keypair = "2.2" @@ -36,11 +39,6 @@ solana-system-interface = "1" solana-transaction = "2.2" solana-transaction-error = "2.2" -pinocchio = "0.8.4" -pinocchio-log = "0.4.0" -pinocchio-pubkey = "0.2.4" - - [workspace.lints.rust] unexpected_cfgs = { level = "allow", check-cfg = [ 'cfg(feature, values("custom-heap", "custom-panic", "anchor-debug", "no-idl", "no-log-ix-name"))', diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..26c075f --- /dev/null +++ b/Makefile @@ -0,0 +1,150 @@ +# LiteSVM Testing - Build and CI Tasks +# +# This Makefile provides fast feedback loops for development and +# standardizes the exact commands that CI should run. + +.PHONY: help check test fmt clean ci-quick ci-full ci-local ci-docker-quick ci-docker-full ci release-validation publish + +# Default target +help: + @echo "LiteSVM Testing Build Tasks" + @echo "" + @echo "Development:" + @echo " check - Fast workspace check (what CI runs)" + @echo " test - Run all tests including Solana programs" + @echo " fmt - Format all code" + @echo " clean - Clean all build artifacts" + @echo "" + @echo "CI Simulation:" + @echo " ci-quick - Fast CI checks (publishable crate only)" + @echo " ci-full - Complete workspace validation" + @echo " ci-local - Full local CI simulation (requires Solana CLI)" + @echo "" + @echo "Docker CI (matches GitHub Actions exactly):" + @echo " ci-docker-quick - Fast CI in Docker container" + @echo " ci-docker-full - Complete CI in Docker container" + @echo " ci - Main CI target (Docker-based)" + @echo "" + @echo "Release:" + @echo " release-validation - Complete release validation" + @echo " publish - Publish to crates.io" + +# Fast workspace validation - exactly what works +check: + @echo "๐Ÿ” Checking workspace..." + cargo check --workspace + @echo "โœ… Workspace check passed" + +# Complete test suite including Solana program compilation +test: + @echo "๐Ÿงช Running all tests (including Solana programs)..." + cargo test --workspace --verbose + @echo "โœ… All tests passed" + +# Format all code +fmt: + @echo "๐ŸŽจ Formatting code..." + cargo fmt --all + @echo "โœ… Code formatted" + +# Check formatting +fmt-check: + @echo "๐ŸŽจ Checking code formatting..." + cargo fmt --all -- --check + @echo "โœ… Code formatting OK" + +# Clean build artifacts +clean: + @echo "๐Ÿงน Cleaning build artifacts..." + cargo clean + @echo "โœ… Clean complete" + +# Quick CI checks - focuses on publishable crate ONLY +ci-quick: + @echo "โšก Running quick CI checks (publishable crate)..." + $(MAKE) fmt-check + @echo "Core library check:" + cargo check --manifest-path crates/litesvm-testing/Cargo.toml --all-features + @echo "Core library clippy:" + cargo clippy --manifest-path crates/litesvm-testing/Cargo.toml --all-features -- -D warnings + @echo "Core library tests:" + cargo test --manifest-path crates/litesvm-testing/Cargo.toml --all-features + @echo "Documentation check:" + cargo doc --manifest-path crates/litesvm-testing/Cargo.toml --all-features --no-deps + @echo "Publish dry run:" + cargo publish --manifest-path crates/litesvm-testing/Cargo.toml --dry-run --allow-dirty + @echo "โœ… Quick CI passed" + +# Full CI validation - what can reliably work in CI +ci-full: + @echo "๐Ÿš€ Running full CI validation..." + $(MAKE) fmt-check + $(MAKE) check + $(MAKE) test + @echo "Core library publish check:" + cargo publish --manifest-path crates/litesvm-testing/Cargo.toml --dry-run --allow-dirty + @echo "โœ… Full CI passed" + +# Local development CI - includes everything possible +ci-local: + @echo "๐Ÿ  Running local CI (includes all checks)..." + $(MAKE) fmt-check + $(MAKE) check + $(MAKE) test + @echo "Core library clippy (all features):" + cargo clippy --manifest-path crates/litesvm-testing/Cargo.toml --all-features -- -D warnings + @echo "Core library publish check:" + cargo publish --manifest-path crates/litesvm-testing/Cargo.toml --dry-run --allow-dirty + @echo "โœ… Local CI passed" + +# Docker-based CI targets (matches CI environment exactly) +ci-docker-quick: + @echo "๐Ÿณ Running quick CI in Docker container..." + @docker pull solanafoundation/anchor:v0.31.1 > /dev/null 2>&1 || true + @mkdir -p ~/.cargo + docker run --rm \ + -v $$(pwd):/workspaces/project \ + -v ~/.cargo:/home/solana/.cargo \ + -w /workspaces/project \ + solanafoundation/anchor:v0.31.1 make ci-quick + +ci-docker-full: + @echo "๐Ÿณ Running full CI in Docker container..." + @docker pull solanafoundation/anchor:v0.31.1 > /dev/null 2>&1 || true + @mkdir -p ~/.cargo + docker run --rm \ + -v $$(pwd):/workspaces/project \ + -v ~/.cargo:/home/solana/.cargo \ + -w /workspaces/project \ + solanafoundation/anchor:v0.31.1 make ci-full + +# Main CI target for GitHub Actions (uses Docker for reproducible environment) +ci: ci-docker-full + +# Release validation - comprehensive checks before publishing +release-validation: + @echo "๐Ÿš€ Running release validation..." + @echo "Verifying tag matches Cargo.toml version..." + @if [ -n "$$TAG_VERSION" ] && [ -n "$$(grep '^version = ' crates/litesvm-testing/Cargo.toml | sed 's/version = "\(.*\)"/\1/')" ]; then \ + CARGO_VERSION=$$(grep '^version = ' crates/litesvm-testing/Cargo.toml | sed 's/version = "\(.*\)"/\1/'); \ + if [ "$$TAG_VERSION" != "$$CARGO_VERSION" ]; then \ + echo "โŒ Tag version $$TAG_VERSION doesn't match Cargo.toml version $$CARGO_VERSION"; \ + exit 1; \ + fi; \ + echo "โœ… Tag version matches Cargo.toml version: $$TAG_VERSION"; \ + fi + $(MAKE) ci-docker-full + @echo "โœ… Release validation passed" + +# Publish to crates.io (requires CARGO_REGISTRY_TOKEN) +publish: + @echo "๐Ÿ“ฆ Publishing to crates.io..." + cargo publish --manifest-path crates/litesvm-testing/Cargo.toml --token $$CARGO_REGISTRY_TOKEN + @echo "โœ… Published to crates.io" + +# Install tools needed for development +install-tools: + @echo "๐Ÿ› ๏ธ Installing development tools..." + cargo install cargo-edit + @command -v act >/dev/null 2>&1 || (echo "Consider installing 'act' for local GitHub Actions: brew install act") + @echo "โœ… Tools installed" \ No newline at end of file diff --git a/crates/litesvm-testing/Cargo.toml b/crates/litesvm-testing/Cargo.toml index 32f6e0c..969fcd5 100644 --- a/crates/litesvm-testing/Cargo.toml +++ b/crates/litesvm-testing/Cargo.toml @@ -2,6 +2,22 @@ name = "litesvm-testing" version = "0.1.0" edition = "2021" +authors = ["LiteSVM Testing Framework Contributors"] +license = "GPL-3.0-or-later" +description = "Comprehensive testing framework for Solana programs using LiteSVM with ergonomic assertions" +repository = "https://github.com/levicook/litesvm-testing" +homepage = "https://github.com/levicook/litesvm-testing" +documentation = "https://docs.rs/litesvm-testing" +readme = "../../README.md" +keywords = ["solana", "testing", "blockchain", "litesvm", "framework"] +categories = ["development-tools::testing"] +include = [ + "src/**/*", + "tests/**/*", + "Cargo.toml", + "../../README.md", + "../../LICENSE", +] [lib] name = "litesvm_testing" @@ -13,7 +29,7 @@ pinocchio = [] [dependencies] litesvm = { workspace = true } -num-traits = "0.2.19" +num-traits = { workspace = true } solana-compute-budget-interface = { workspace = true } solana-instruction = { workspace = true } solana-keypair = { workspace = true } diff --git a/crates/litesvm-testing/src/anchor_testing/build.rs b/crates/litesvm-testing/src/anchor_testing/build.rs index 954ca65..ae4aea3 100644 --- a/crates/litesvm-testing/src/anchor_testing/build.rs +++ b/crates/litesvm-testing/src/anchor_testing/build.rs @@ -16,7 +16,7 @@ pub fn build_anchor_program>(program_path: P) { // Build the anchor program let output = Command::new("cargo") - .args(&[ + .args([ "build-sbf", "--manifest-path", &program_manifest.to_string_lossy(), diff --git a/crates/litesvm-testing/src/lib.rs b/crates/litesvm-testing/src/lib.rs index be043da..0eda5e4 100644 --- a/crates/litesvm-testing/src/lib.rs +++ b/crates/litesvm-testing/src/lib.rs @@ -1,5 +1,5 @@ //! # LiteSVM Testing Utilities -//! Copyright (C) 2024 Levi Cook - Licensed under GPL v3.0-or-later +//! Copyright (C) 2024 LiteSVM Testing Framework Contributors - Licensed under GPL v3.0-or-later //! //! A comprehensive testing framework for Solana programs using LiteSVM. Provides ergonomic, //! type-safe assertions for transaction results, logs, and all levels of Solana errors. diff --git a/crates/litesvm-testing/src/pinocchio_testing/build.rs b/crates/litesvm-testing/src/pinocchio_testing/build.rs index 1b1eb2a..b06062e 100644 --- a/crates/litesvm-testing/src/pinocchio_testing/build.rs +++ b/crates/litesvm-testing/src/pinocchio_testing/build.rs @@ -30,12 +30,10 @@ //! ## Example usage: //! //! In your test crate's `build.rs`: -//! ```rust +//! ```rust,no_run //! use litesvm_testing::pinocchio_testing::build_pinocchio_program; //! -//! fn main() { -//! build_pinocchio_program("../my-pinocchio-program"); -//! } +//! build_pinocchio_program("../my-pinocchio-program"); //! ``` use std::{path::Path, process::Command}; @@ -55,13 +53,11 @@ use std::{path::Path, process::Command}; /// /// # Example /// -/// ```rust +/// ```rust,no_run /// // In build.rs /// use litesvm_testing::pinocchio_testing::build_pinocchio_program; /// -/// fn main() { -/// build_pinocchio_program("../simple-pinocchio-program"); -/// } +/// build_pinocchio_program("../simple-pinocchio-program"); /// ``` /// /// For custom feature configurations, use [`build_pinocchio_program_with_features`]. @@ -89,8 +85,10 @@ pub fn build_pinocchio_program>(program_path: P) { /// /// # Example /// -/// ```rust +/// ```rust,no_run /// // Custom features for specialized builds +/// use litesvm_testing::pinocchio_testing::build_pinocchio_program_with_features; +/// /// build_pinocchio_program_with_features( /// "../my-program", /// &["bpf-entrypoint", "custom-feature", "debug-mode"] @@ -122,7 +120,7 @@ pub fn build_pinocchio_program_with_features>(program_path: P, fe // Build the pinocchio program let output = Command::new("cargo") - .args(&[ + .args([ "build-sbf", "--manifest-path", &program_manifest.to_string_lossy(),