armature-framework 0.2.2

A modern, type-safe HTTP framework for Rust inspired by Angular and NestJS. Features dependency injection, decorators, middleware, authentication (JWT/OAuth2/SAML), validation, OpenAPI/Swagger, caching, job queues, and observability.
# Publishing Guide

Guide for publishing Armature crates to crates.io.

## Table of Contents

- [Overview]#overview
- [Prerequisites]#prerequisites
- [Publishing Scripts]#publishing-scripts
- [Publish Order]#publish-order
- [Step-by-Step Publishing]#step-by-step-publishing
- [Troubleshooting]#troubleshooting

---

## Overview

The Armature workspace contains 47+ crates with inter-dependencies. Publishing to crates.io requires:

1. **Correct Order**: Crates must be published in dependency order
2. **Version Dependencies**: Path dependencies must be converted to version dependencies
3. **Required Metadata**: All crates need license, description, and other metadata

Two scripts automate this process:

- `scripts/publish.sh` - Publishes crates in correct order
- `scripts/prepare-publish.sh` - Converts path deps to version deps

---

## Prerequisites

### 1. crates.io Account

Create an account at [crates.io](https://crates.io) and log in:

```bash
cargo login
```

Or set the token via environment variable:

```bash
export CARGO_REGISTRY_TOKEN=your-token-here
```

### 2. Required Metadata

Each crate's `Cargo.toml` must include:

```toml
[package]
name = "armature-xxx"
version = "0.1.0"
license = "MIT"  # or your license
description = "Description of this crate"
repository = "https://github.com/pegasusheavy/armature"
```

### 3. Check Readiness

```bash
./scripts/publish.sh --check
```

Output shows which crates are ready and which need fixes:

```
✓ armature-log
✓ armature-core
! armature-auth: Missing 'license' field
! armature-queue: 3 path deps (run prepare-publish.sh)
```

---

## Publishing Scripts

### publish.sh

Main publishing script that handles dependency order.

```bash
# Show publish order (dry run)
# Also shows which versions are already on crates.io
./scripts/publish.sh --dry-run

# Check all crates are ready
./scripts/publish.sh --check

# Publish all crates
# Automatically skips versions already published on crates.io
./scripts/publish.sh

# Publish single crate
./scripts/publish.sh --single armature-log

# Resume from a specific crate
./scripts/publish.sh --from armature-auth

# Skip problematic crates
./scripts/publish.sh --skip armature-cli --skip armature-ferron

# Force republish even if version exists on crates.io
./scripts/publish.sh --force

# Skip verification (faster, less safe)
./scripts/publish.sh --no-verify
```

### prepare-publish.sh

Converts path dependencies to version dependencies for crates.io.

```bash
# Prepare for publishing
./scripts/prepare-publish.sh --version 0.1.0

# Preview changes (dry run)
./scripts/prepare-publish.sh --version 0.1.0 --dry-run

# Restore after publishing
./scripts/prepare-publish.sh --restore
```

---

## Publish Order

The script automatically computes the correct publish order using topological sort. Crates with no workspace dependencies are published first.

Example order (abbreviated):

```
1. armature-log           # No deps
2. armature-macros-utils  # No deps
3. armature-core          # Depends on armature-log
4. armature-jwt           # Depends on armature-core
5. armature-auth          # Depends on armature-jwt, armature-core
6. armature-cache         # Depends on armature-core, armature-redis
...
```

View the full order with version status:

```bash
./scripts/publish.sh --dry-run
```

Output shows crates.io status:

```
1. armature-log (v0.1.0) [on crates.io]     # Already published
2. armature-core (v0.1.0) [new version]     # New version to publish
3. armature-auth (v0.1.0) [new crate]       # First time publishing
```

---

## Version Verification

The publish script automatically checks crates.io before publishing:

- **Already published versions are skipped** (no errors)
- **New versions are published** normally
- **New crates** (never published) are published normally

### Behavior

```bash
./scripts/publish.sh
```

Output:
```
[INFO] Publishing armature-log v0.1.0...
[WARN] armature-log v0.1.0 is already published on crates.io (use --force to republish)
[INFO] Publishing armature-core v0.1.1...
[SUCCESS] armature-core v0.1.1 published successfully

Publishing complete!
  Published: 1
  Already on crates.io: 1
  Skipped: 0
```

### Force Republish

To attempt publishing even if the version exists:

```bash
./scripts/publish.sh --force
```

Note: crates.io will still reject duplicate versions. Use `--force` when:
- You need to retry a failed publish
- The API check returned an error

---

## Step-by-Step Publishing

### 1. Check Current State

```bash
./scripts/publish.sh --check
```

Fix any issues reported (missing metadata, etc.).

### 2. Prepare for Publishing

```bash
# Backup Cargo.toml files and convert path deps
./scripts/prepare-publish.sh --version 0.1.0
```

This:
- Creates backups in `.publish-backup/`
- Converts `path = "../armature-xxx"` to `version = "0.1.0"`

### 3. Review Changes

```bash
git diff
```

Verify the conversions look correct.

### 4. Publish

```bash
# Dry run first
./scripts/publish.sh --dry-run

# Then publish
./scripts/publish.sh
```

The script:
- Publishes crates in dependency order
- Waits 30 seconds between publishes for crates.io indexing
- Shows progress

### 5. Restore for Development

```bash
./scripts/prepare-publish.sh --restore
```

This restores the original `Cargo.toml` files with path dependencies.

---

## Troubleshooting

### "Rate limit exceeded"

crates.io has rate limits. The script waits 30 seconds between publishes, but you may need to wait longer:

```bash
# Increase delay (edit PUBLISH_DELAY in publish.sh)
PUBLISH_DELAY=60
```

### "Dependency not found"

The dependency hasn't been indexed yet. Wait a minute and retry:

```bash
./scripts/publish.sh --from armature-xxx
```

### "Missing required field"

Add the missing field to the crate's `Cargo.toml`:

```toml
[package]
license = "MIT"
description = "Your description"
```

### "Package already exists"

The version is already published. The script now automatically detects this and skips the crate:

```
[WARN] armature-xxx v0.1.0 is already published on crates.io
```

To publish a new version, bump the version in `Cargo.toml`:

```toml
version = "0.1.1"
```

### Partial Publish Failed

Resume from where it stopped:

```bash
./scripts/publish.sh --from armature-xxx
```

Or skip the problematic crate:

```bash
./scripts/publish.sh --skip armature-xxx
```

---

## Best Practices

### 1. Always Dry Run First

```bash
./scripts/publish.sh --dry-run
```

### 2. Publish Minor Updates Frequently

Small, frequent releases are easier to manage than large batches.

### 3. Use Semantic Versioning

- `0.1.0``0.1.1`: Bug fixes
- `0.1.0``0.2.0`: New features
- `0.1.0``1.0.0`: Breaking changes

### 4. Test Before Publishing

```bash
cargo test --all
cargo clippy --all
```

### 5. Keep Backups

The `prepare-publish.sh` script creates backups, but also consider:

```bash
git stash
# or
git checkout -b publish-prep
```

---

## Summary

### Quick Reference

```bash
# Check readiness
./scripts/publish.sh --check

# Prepare (convert path → version deps)
./scripts/prepare-publish.sh --version 0.1.0

# Publish
./scripts/publish.sh

# Restore (version → path deps)
./scripts/prepare-publish.sh --restore
```

### Environment

```bash
CARGO_REGISTRY_TOKEN=xxx  # crates.io token
```

---

**Happy publishing!** 📦