Skip to main content

intentional_core/
model.rs

1// ---
2// relationships:
3//   implements: intent-driven-polyglot-release
4// ---
5
6//! Shared release domain values.
7
8use serde::{Deserialize, Serialize};
9use std::fmt;
10use std::str::FromStr;
11
12/// Semantic version change declared by an intent.
13#[derive(
14    Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash,
15)]
16#[serde(rename_all = "lowercase")]
17pub enum Bump {
18    /// No change.
19    #[default]
20    None,
21    /// Backwards-compatible bug fix.
22    Patch,
23    /// Backwards-compatible feature.
24    Minor,
25    /// Breaking change.
26    Major,
27}
28
29impl fmt::Display for Bump {
30    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31        formatter.write_str(match self {
32            Self::None => "none",
33            Self::Patch => "patch",
34            Self::Minor => "minor",
35            Self::Major => "major",
36        })
37    }
38}
39
40impl FromStr for Bump {
41    type Err = String;
42
43    fn from_str(value: &str) -> std::result::Result<Self, Self::Err> {
44        match value {
45            "patch" => Ok(Self::Patch),
46            "minor" => Ok(Self::Minor),
47            "major" => Ok(Self::Major),
48            _ => Err(format!("expected major, minor, or patch; got {value}")),
49        }
50    }
51}
52
53/// How a version projection is materialized.
54#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
55#[serde(rename_all = "lowercase")]
56pub enum ProjectionMode {
57    /// Version is written for a source-controlled release commit.
58    Committed,
59    /// Version is written only for build-time stamping.
60    Injected,
61    /// No manifest version is written.
62    None,
63}
64
65/// How adoption translates pending bumps written under component semantics.
66///
67/// Changesets and `contract-1` component configs read a bump name as the
68/// version component to increment. Intentional reads it as change
69/// significance. Adoption translates pending bumps once.
70#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
71#[serde(rename_all = "lowercase")]
72pub enum BumpTranslation {
73    /// Rewrite bumps so that the next versions match the source tool.
74    #[default]
75    Parity,
76    /// Keep bump names and read them as change significance.
77    Significance,
78}
79
80impl fmt::Display for BumpTranslation {
81    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
82        formatter.write_str(match self {
83            Self::Parity => "parity",
84            Self::Significance => "significance",
85        })
86    }
87}
88
89impl FromStr for BumpTranslation {
90    type Err = String;
91
92    fn from_str(value: &str) -> std::result::Result<Self, Self::Err> {
93        match value {
94            "parity" => Ok(Self::Parity),
95            "significance" => Ok(Self::Significance),
96            _ => Err(format!("expected parity or significance; got {value}")),
97        }
98    }
99}
100
101/// Whether a discovered release unit participates in releases.
102#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, PartialEq, Eq)]
103#[serde(rename_all = "lowercase")]
104pub enum ReleaseUnitDisposition {
105    /// The release unit is configured and eligible for release.
106    #[default]
107    Managed,
108    /// The release unit remains configured, but any release requiring it is blocked.
109    Suspended,
110}
111
112/// Version-authority role of a release-unit tag.
113#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
114#[serde(rename_all = "lowercase")]
115pub enum TagRole {
116    /// The single tag stream used to discover the release unit's current version.
117    Primary,
118    /// An additional release record carrying the same logical version.
119    Projection,
120}
121
122/// Executor-declared phase required to create a configured tag.
123#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
124#[serde(rename_all = "kebab-case")]
125pub enum TagPhase {
126    /// The executor declares that publication has not begun.
127    BeforePublication,
128    /// The executor declares that publication has completed.
129    AfterPublication,
130}
131
132impl fmt::Display for TagPhase {
133    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
134        formatter.write_str(match self {
135            Self::BeforePublication => "before-publication",
136            Self::AfterPublication => "after-publication",
137        })
138    }
139}
140
141/// Manifest or generic format adapter used by a projection.
142#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Hash)]
143#[serde(rename_all = "lowercase")]
144pub enum Adapter {
145    /// npm `package.json`.
146    Npm,
147    /// Cargo `Cargo.toml`.
148    Cargo,
149    /// Dart/Flutter `pubspec.yaml`.
150    Pub,
151    /// PEP 621 `pyproject.toml`.
152    Python,
153    /// MSBuild project file.
154    Msbuild,
155    /// Go module file.
156    Go,
157    /// Generic JSON file.
158    Json,
159    /// Generic TOML file.
160    Toml,
161    /// Generic YAML file.
162    Yaml,
163}
164
165impl Adapter {
166    /// Whether the adapter requires an explicit pointer.
167    pub fn requires_pointer(self) -> bool {
168        matches!(self, Self::Json | Self::Toml | Self::Yaml)
169    }
170
171    /// Whether the projection participates in dependency range rewriting.
172    pub fn ecosystem(self) -> Option<&'static str> {
173        match self {
174            Self::Npm => Some("npm"),
175            Self::Cargo => Some("cargo"),
176            Self::Pub => Some("pub"),
177            Self::Python => Some("python"),
178            Self::Msbuild => Some("msbuild"),
179            Self::Go => Some("go"),
180            Self::Json | Self::Toml | Self::Yaml => None,
181        }
182    }
183}