ephemeris_forge_github/config/rulesets/rules/
list.rs1use ephemeris_forge::FieldDiff;
2use facet::Facet;
3
4use super::{
5 CodeScanningRule, DeploymentsRule, MergeQueueRule, PatternRule, PullRequestRule,
6 StatusChecksRule, UpdateRule, WorkflowsRule,
7};
8
9macro_rules! rules {
14 (
15 $($kind:ident $field:ident $(: $ty:ty)? => $variant:ident $(#[doc = $doc:literal])+;)+
16 ) => {
17 #[derive(Clone, Debug, Eq, Facet, PartialEq)]
19 #[facet(deny_unknown_fields)]
20 pub struct Rules {
21 $(
22 $(#[doc = $doc])+
23 pub $field: rules!(@field $kind $($ty)?),
24 )+
25 }
26
27 #[derive(Facet)]
29 #[repr(u8)]
30 #[expect(dead_code, reason = "the rule payloads are only read by the encoder")]
31 #[facet(tag = "type", content = "parameters", rename_all = "snake_case")]
32 pub(crate) enum RuleRef<'a> {
33 $($variant $((&'a $ty))?,)+
34 }
35
36 impl Rules {
37 #[must_use]
39 pub(crate) const fn none() -> Self {
40 Self { $($field: rules!(@none $kind),)+ }
41 }
42
43 pub(crate) fn entries(&self) -> Vec<RuleRef<'_>> {
45 let mut entries = Vec::new();
46 $(rules!(@push $kind entries self $field $variant);)+
47 entries
48 }
49
50 pub(crate) fn absorb<D: RuleDecoder>(
57 &mut self,
58 kind: &str,
59 decoder: &D,
60 ) -> Result<bool, D::Error> {
61 match kind {
62 $(stringify!($field) => rules!(@read $kind self decoder $field),)+
63 _ => return Ok(false),
64 }
65 Ok(true)
66 }
67
68 pub(crate) fn compare(&self, live: Option<&Self>, diff: &mut FieldDiff) {
70 $(diff.compare(
71 concat!("rules.", stringify!($field)),
72 live.map(|live| &live.$field),
73 &self.$field,
74 );)+
75 }
76 }
77 };
78 (@field switch) => { bool };
79 (@field rule $ty:ty) => { Option<$ty> };
80 (@none switch) => { false };
81 (@none rule) => { None };
82 (@push switch $entries:ident $rules:ident $field:ident $variant:ident) => {
83 if $rules.$field {
84 $entries.push(RuleRef::$variant);
85 }
86 };
87 (@push rule $entries:ident $rules:ident $field:ident $variant:ident) => {
88 $entries.extend($rules.$field.as_ref().map(RuleRef::$variant));
89 };
90 (@read switch $rules:ident $decoder:ident $field:ident) => {
91 $rules.$field = true
92 };
93 (@read rule $rules:ident $decoder:ident $field:ident) => {
94 $rules.$field = Some($decoder.parameters()?)
95 };
96}
97
98pub(crate) trait RuleDecoder {
100 type Error;
102
103 fn parameters<T: for<'a> Facet<'a>>(&self) -> Result<T, Self::Error>;
108}
109
110rules! {
111 rule required_status_checks: StatusChecksRule => RequiredStatusChecks
112 #[doc = "Require status checks to pass."];
113 rule pull_request: PullRequestRule => PullRequest
114 #[doc = "Require changes to arrive through a pull request."];
115 switch required_signatures => RequiredSignatures
116 #[doc = "Require signed commits."];
117 switch non_fast_forward => NonFastForward
118 #[doc = "Block force pushes."];
119 switch deletion => Deletion
120 #[doc = "Block deleting matching refs."];
121 switch creation => Creation
122 #[doc = "Block creating matching refs."];
123 switch required_linear_history => RequiredLinearHistory
124 #[doc = "Require a linear history."];
125 rule update: UpdateRule => Update
126 #[doc = "Restrict updating matching refs."];
127 rule required_deployments: DeploymentsRule => RequiredDeployments
128 #[doc = "Require successful deployments."];
129 rule commit_message_pattern: PatternRule => CommitMessagePattern
130 #[doc = "Require commit messages to match a pattern."];
131 rule commit_author_email_pattern: PatternRule => CommitAuthorEmailPattern
132 #[doc = "Require commit author emails to match a pattern."];
133 rule committer_email_pattern: PatternRule => CommitterEmailPattern
134 #[doc = "Require committer emails to match a pattern."];
135 rule branch_name_pattern: PatternRule => BranchNamePattern
136 #[doc = "Require branch names to match a pattern."];
137 rule tag_name_pattern: PatternRule => TagNamePattern
138 #[doc = "Require tag names to match a pattern."];
139 rule workflows: WorkflowsRule => Workflows
140 #[doc = "Require workflows to pass."];
141 rule code_scanning: CodeScanningRule => CodeScanning
142 #[doc = "Require code scanning results."];
143 rule merge_queue: MergeQueueRule => MergeQueue
144 #[doc = "Require a merge queue."];
145}