Skip to main content

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}