abbaye/builders/mod.rs
1use miette::Result;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use std::path::PathBuf;
5
6pub mod archive;
7pub mod cargo;
8pub mod script;
9
10use archive::{ArchiveBuilder, ArchiveBuilderConfig};
11use cargo::{CargoBuilder, CargoBuilderConfig, CargoDocBuilder, CargoDocBuilderConfig};
12use script::{ScriptBuilder, ScriptBuilderConfig};
13
14#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)]
15#[serde(tag = "type", rename_all = "snake_case")]
16pub enum AnyBuilder {
17 /// Creates a `.tar.gz` archive of the source tree, automatically excluding
18 /// files and directories matched by any `.gitignore` found in the hierarchy.
19 ///
20 /// ```toml
21 /// [[builders]]
22 /// type = "archive"
23 /// source_dir = "." # optional, defaults to CWD
24 /// output = "myproject-1.0.0.tar.gz" # optional, defaults to source.tar.gz
25 /// prefix = "myproject-1.0.0" # optional, defaults to source_dir name
26 /// ```
27 Archive(ArchiveBuilderConfig),
28
29 /// Compiles the crate in release mode with `cargo build --release`.
30 /// One or more target triples can be specified for cross-compilation;
31 /// omitting `targets` builds for the host platform.
32 ///
33 /// ```toml
34 /// [[builders]]
35 /// type = "cargo"
36 /// targets = ["x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl"]
37 /// manifest_path = "Cargo.toml" # optional
38 /// ```
39 Cargo(CargoBuilderConfig),
40
41 /// Generates API documentation with `cargo doc`.
42 /// Returns the per-crate doc directory (e.g. `target/doc/my_crate`) as an
43 /// artifact so it can be published or archived by a later pipeline step.
44 ///
45 /// ```toml
46 /// [[builders]]
47 /// type = "cargo_doc"
48 /// no_deps = true # optional, skip dependency docs
49 /// manifest_path = "Cargo.toml" # optional
50 /// ```
51 CargoDoc(CargoDocBuilderConfig),
52
53 /// Runs an arbitrary sequence of shell commands and collects declared
54 /// output paths as release artifacts.
55 ///
56 /// Each script line is passed to `sh -c`; the build fails immediately if
57 /// any command exits with a non-zero status.
58 ///
59 /// ```toml
60 /// [[builders]]
61 /// type = "script"
62 /// script = [
63 /// "make release",
64 /// "strip target/mybin",
65 /// ]
66 /// outputs = ["target/mybin"]
67 /// ```
68 Script(ScriptBuilderConfig),
69}
70
71impl AnyBuilder {
72 pub async fn build(&self, version: &str) -> Result<Vec<ArtifactPath>> {
73 match self {
74 Self::Archive(config) => ArchiveBuilder.build(config.clone(), version).await,
75 Self::Cargo(config) => CargoBuilder.build(config.clone(), version).await,
76 Self::CargoDoc(config) => CargoDocBuilder.build(config.clone(), version).await,
77 Self::Script(config) => ScriptBuilder.build(config.clone(), version).await,
78 }
79 }
80}
81
82pub struct ArtifactPath {
83 pub path: PathBuf,
84 pub name: String,
85 /// Lowercase hexadecimal SHA1 digest of the artifact's contents, if computed.
86 pub hash: Option<String>,
87}
88
89#[allow(async_fn_in_trait)]
90pub trait Builder {
91 type ConfigType: Default + for<'de> Deserialize<'de> + Clone;
92
93 /// Run the builder and return the produced artifacts.
94 ///
95 /// `version` is the abbaye release version currently being built (e.g.
96 /// `"1.2.3"`). Implementations that spawn subprocesses must expose it as
97 /// the `ABBAYE_BUILDING_VERSION` environment variable.
98 async fn build(&self, config: Self::ConfigType, version: &str) -> Result<Vec<ArtifactPath>>;
99}