1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! # ferro-deployments
//!
//! Immutable deployment rows and atomic pointer promotion for the Ferro framework.
//!
//! ## Overview
//!
//! Each deployment is recorded as an append-only row in the `deployments` table.
//! A per-owner `deployment_pointers` row tracks which deployment is currently active
//! and which was the previous one, enabling atomic promotion and rollback.
//!
//! Artifact storage is abstracted through [`ferro_storage`] so the same crate works
//! with local filesystem, S3, or any other configured driver. The artifact shape is
//! opaque — static site bundles, JSON-UI spec bundles, SSR manifests, and any other
//! byte sequence all fit without crate-level assumptions.
//!
//! ## Quick Start
//!
//! Register both migration helpers in your `Migrator`, then use
//! [`DeploymentConfig::from_env`] to read operator configuration.
//!
//! ```rust,ignore
//! use ferro_deployments::{CreateDeploymentsTable, CreateDeploymentPointersTable};
//!
//! impl MigratorTrait for Migrator {
//! fn migrations() -> Vec<Box<dyn MigrationTrait>> {
//! vec![
//! Box::new(CreateDeploymentsTable),
//! Box::new(CreateDeploymentPointersTable),
//! ]
//! }
//! }
//! ```
//!
//! ## Full lifecycle example (criterion 5 — JSON spec artifact)
//!
//! This example stores a JSON spec bundle through the full lifecycle API:
//! `create` → `store` → `mark_ready` → `promote` → `retrieve`. The artifact
//! is opaque bytes — the crate makes no assumption about content type.
//!
//! ```rust
//! # use ferro_deployments::{
//! # CreateDeploymentPointersTable, CreateDeploymentsTable, DeploymentStorage,
//! # Deployments, DeploymentStatus, StorageDeploymentStorage,
//! # };
//! # use ferro_storage::{DiskConfig, Storage, StorageConfig};
//! # use bytes::Bytes;
//! # use sea_orm::Database;
//! # use sea_orm_migration::MigratorTrait;
//! #
//! # struct DocMigrator;
//! # #[async_trait::async_trait]
//! # impl MigratorTrait for DocMigrator {
//! # fn migrations() -> Vec<Box<dyn sea_orm_migration::MigrationTrait>> {
//! # vec![
//! # Box::new(CreateDeploymentsTable),
//! # Box::new(CreateDeploymentPointersTable),
//! # ]
//! # }
//! # }
//! #
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! // Connect to an in-memory SQLite database and run migrations.
//! let conn = Database::connect("sqlite::memory:").await.unwrap();
//! DocMigrator::up(&conn, None).await.unwrap();
//!
//! // Create a deployment handle and register a new build.
//! let deps = Deployments::new(conn);
//! let d = deps.create("project:demo", Some("sha-abcdef")).await.unwrap();
//! assert_eq!(d.status, DeploymentStatus::Building);
//!
//! // Build a memory-backed storage adapter and store a JSON spec bundle.
//! let storage_config = StorageConfig::new("mem").disk("mem", DiskConfig::memory());
//! let disk = Storage::with_storage_config(storage_config).disk("mem").unwrap();
//! let storage = StorageDeploymentStorage::new(disk);
//!
//! let spec_json = Bytes::from_static(br#"{"intent":"browse","fields":[]}"#);
//! storage.store(d.id, "spec.json", spec_json.clone()).await.unwrap();
//!
//! // Transition the deployment to ready, recording artifact location and size.
//! let artifact_location = format!("deployments/{}/", d.id);
//! deps.mark_ready(d.id, &artifact_location, spec_json.len() as i64)
//! .await
//! .unwrap();
//!
//! // Atomically promote the deployment.
//! let previous = deps.promote("project:demo", d.id).await.unwrap();
//! assert!(previous.is_none(), "first promotion has no previous deployment");
//!
//! // Retrieve the stored artifact and verify round-trip fidelity.
//! let retrieved = storage.retrieve(d.id, "spec.json").await.unwrap();
//! assert_eq!(retrieved, spec_json);
//! # });
//! ```
pub
pub
pub use DeploymentConfig;
pub use ;
pub use Error;
pub use ;
pub use ;